100 #include "asterisk/stasis_bridges.h"
101 #include "asterisk/stasis_channels.h"
127 static unsigned int optimization_id;
130 #define BRIDGE_ARRAY_START 128
133 #define BRIDGE_ARRAY_GROW 32
136 #define BLINDTRANSFER "BLINDTRANSFER"
139 #define ATTENDEDTRANSFER "ATTENDEDTRANSFER"
141 static void cleanup_video_mode(
struct ast_bridge *bridge);
186 static void bridge_manager_service_req(
struct ast_bridge *bridge)
217 if (ast_strlen_zero(technology->
name)
219 || !technology->
write) {
220 ast_log(LOG_WARNING,
"Bridge technology %s failed registration sanity check.\n",
229 if ((!strcasecmp(current->
name, technology->
name)) || (current == technology)) {
230 ast_log(LOG_WARNING,
"A bridge technology of %s already claims to exist in our world.\n",
238 technology->
mod = module;
244 AST_RWLIST_INSERT_BEFORE_CURRENT(technology,
entry);
249 AST_RWLIST_TRAVERSE_SAFE_END;
258 ast_verb(5,
"Registered bridge technology %s\n", technology->
name);
271 if (current == technology) {
272 AST_RWLIST_REMOVE_CURRENT(
entry);
273 ast_verb(5,
"Unregistered bridge technology %s\n", technology->
name);
277 AST_RWLIST_TRAVERSE_SAFE_END;
281 return current ? 0 : -1;
294 ast_debug(1,
"Bridge %s: queueing action type:%u sub:%d\n",
300 bridge_manager_service_req(bridge);
311 bridge_queue_action_nodup(bridge, dup);
315 void bridge_dissolve(
struct ast_bridge *bridge,
int cause)
329 cause = AST_CAUSE_NORMAL_CLEARING;
331 bridge->
cause = cause;
333 ast_debug(1,
"Bridge %s: dissolving bridge with cause %d(%s)\n",
365 bridge_dissolve(bridge, 0);
374 bridge_dissolve(bridge, 0);
385 static void bridge_reconfigured_connected_line_update(
struct ast_bridge *bridge)
389 unsigned char data[1024];
392 if (!bridge_channel ||
397 ast_check_hangup_locked(bridge_channel->
chan) ||
398 ast_check_hangup_locked(peer->chan)) {
404 ast_channel_lock(bridge_channel->
chan);
406 ast_channel_unlock(bridge_channel->
chan);
412 ast_channel_lock(peer->chan);
414 ast_channel_unlock(peer->chan);
436 ast_debug(1,
"Bridge %s: %p(%s) is joining %s technology\n",
437 bridge->
uniqueid, bridge_channel, ast_channel_name(bridge_channel->
chan),
442 ast_debug(1,
"Bridge %s: %p(%s) failed to join %s technology (Kicking it out)\n",
443 bridge->
uniqueid, bridge_channel, ast_channel_name(bridge_channel->
chan),
459 bridge_channel->
bridge, bridge_channel);
474 static void bridge_complete_join(
struct ast_bridge *bridge)
490 bridge_channel_queue_deferred_frames(bridge_channel);
494 bridge_channel_complete_join(bridge, bridge_channel);
507 ast_debug(1,
"Bridge technology %s is suspended. Skipping.\n",
512 ast_debug(1,
"Bridge technology %s does not have any capabilities we want.\n",
517 ast_debug(1,
"Bridge technology %s has less preference than %s (%u <= %u). Skipping.\n",
522 ast_debug(1,
"Bridge technology %s is not compatible with properties of existing bridge.\n",
527 ast_debug(1,
"Bridge technology %s is not running, skipping.\n", current->
name);
560 static void bridge_tech_deferred_destroy(
struct ast_bridge *bridge,
struct ast_frame *action)
565 .tech_pvt = deferred->tech_pvt,
567 .name = bridge->
name,
571 ast_debug(1,
"Bridge %s: calling %s technology destructor (deferred, dummy)\n",
591 int in_destructor = !
ao2_ref(bridge, 0);
597 bridge_tech_deferred_destroy(bridge, action);
622 static void bridge_handle_actions(
struct ast_bridge *bridge)
629 bridge_action_bridge(bridge, action);
640 static void destroy_bridge(
void *obj)
644 ast_debug(1,
"Bridge %s: actually destroying %s bridge, nobody wants it anymore\n",
648 bridge_topics_destroy(bridge);
653 bridge_handle_actions(bridge);
659 ast_debug(1,
"Bridge %s: calling %s bridge destructor\n",
665 ast_debug(1,
"Bridge %s: calling %s technology stop\n",
672 ast_debug(1,
"Bridge %s: calling %s technology destructor\n",
685 cleanup_video_mode(bridge);
719 ast_log(LOG_ERROR,
"Virtual method table for bridge class %s not complete.\n",
720 v_table && v_table->
name ? v_table->
name :
"<unknown>");
725 bridge = ao2_alloc(size, destroy_bridge);
744 char uuid_hold[AST_UUID_STR_LEN];
750 if (!ast_strlen_zero(
id)) {
757 if (!ast_strlen_zero(creator)) {
761 ast_set_flag(&self->feature_flags, flags);
762 self->allowed_capabilities = capabilities;
765 if (bridge_topics_init(
self) != 0) {
766 ast_log(LOG_WARNING,
"Bridge %s: Could not initialize topics\n",
775 if (!self->technology) {
776 ast_log(LOG_WARNING,
"Bridge %s: Could not create class %s. No technology to support it.\n",
777 self->uniqueid, self->v_table->name);
783 ast_debug(1,
"Bridge %s: calling %s technology constructor\n",
784 self->uniqueid, self->technology->name);
785 if (self->technology->create && self->technology->create(
self)) {
786 ast_log(LOG_WARNING,
"Bridge %s: failed to setup bridge technology %s\n",
787 self->uniqueid, self->technology->name);
791 ast_debug(1,
"Bridge %s: calling %s technology start\n",
792 self->uniqueid, self->technology->name);
793 if (self->technology->start && self->technology->start(
self)) {
794 ast_log(LOG_WARNING,
"Bridge %s: failed to start bridge technology %s\n",
795 self->uniqueid, self->technology->name);
800 if (!(flags & AST_BRIDGE_FLAG_INVISIBLE)) {
821 static void bridge_base_destroy(
struct ast_bridge *
self)
832 static void bridge_base_dissolving(
struct ast_bridge *
self)
884 self->reconfigured = 1;
898 static int bridge_base_get_merge_priority(
struct ast_bridge *
self)
925 .destroy = bridge_base_destroy,
926 .dissolving = bridge_base_dissolving,
927 .push = bridge_base_push,
928 .pull = bridge_base_pull,
929 .notify_masquerade = bridge_base_notify_masquerade,
930 .get_merge_priority = bridge_base_get_merge_priority,
931 .push_peek = bridge_base_push_peek,
938 bridge = bridge_alloc(
sizeof(
struct ast_bridge), &ast_bridge_base_v_table);
946 ast_debug(1,
"Bridge %s: telling all channels to leave the party\n", bridge->
uniqueid);
948 bridge_dissolve(bridge, cause);
972 static int smart_bridge_operation(
struct ast_bridge *bridge)
974 uint32_t new_capabilities;
983 .name = bridge->
name,
988 ast_debug(1,
"Bridge %s is dissolved, not performing smart bridge operation.\n",
1000 if (!new_capabilities
1009 if (!new_technology) {
1010 int is_compatible = 0;
1013 is_compatible = old_technology->
compatible(bridge);
1021 if (is_compatible) {
1022 ast_debug(1,
"Bridge %s could not get a new technology, staying with old technology.\n",
1026 ast_log(LOG_WARNING,
"Bridge %s has no technology available to support it.\n",
1030 if (new_technology == old_technology) {
1031 ast_debug(1,
"Bridge %s is already using the new technology.\n",
1037 if (old_technology->
destroy) {
1045 .data.ptr = &deferred_tech_destroy,
1046 .datalen =
sizeof(deferred_tech_destroy),
1054 if (!deferred_action) {
1059 deferred_action = NULL;
1067 ast_verb(4,
"Bridge %s: switching from %s technology to %s\n",
1080 ast_debug(1,
"Bridge %s: calling %s technology constructor\n",
1082 if (new_technology->
create && new_technology->
create(bridge)) {
1083 ast_log(LOG_WARNING,
"Bridge %s: failed to setup bridge technology %s\n",
1098 ast_debug(1,
"Bridge %s: moving %p(%s) to dummy bridge temporarily\n",
1099 bridge->
uniqueid, bridge_channel, ast_channel_name(bridge_channel->
chan));
1114 ast_debug(1,
"Bridge %s: %p(%s) is leaving %s technology (dummy)\n",
1115 dummy_bridge.
uniqueid, bridge_channel, ast_channel_name(bridge_channel->
chan),
1116 old_technology->
name);
1117 if (old_technology->
leave) {
1118 old_technology->
leave(&dummy_bridge, bridge_channel);
1132 ast_debug(1,
"Bridge %s: calling %s technology stop\n",
1134 if (old_technology->
stop) {
1135 old_technology->
stop(&dummy_bridge);
1140 bridge_channel_complete_join(bridge, bridge_channel);
1143 ast_debug(1,
"Bridge %s: calling %s technology start\n",
1145 if (new_technology->
start && new_technology->
start(bridge)) {
1146 ast_log(LOG_WARNING,
"Bridge %s: failed to start bridge technology %s\n",
1155 if (old_technology->
destroy) {
1156 ast_debug(1,
"Bridge %s: deferring %s technology destructor\n",
1158 bridge_queue_action_nodup(bridge, deferred_action);
1160 ast_debug(1,
"Bridge %s: calling %s technology destructor\n",
1179 ast_channel_lock(bridge_channel->
chan);
1181 if (!ast_strlen_zero(play_file)) {
1187 ast_channel_unlock(bridge_channel->
chan);
1203 static void check_bridge_play_sounds(
struct ast_bridge *bridge)
1208 check_bridge_play_sound(bridge_channel);
1233 const char *c0_name;
1234 const char *c1_name;
1235 const char *c0_pvtid = NULL;
1236 const char *c1_pvtid = NULL;
1237 #define UPDATE_BRIDGE_VARS_GET(chan, name, pvtid) \
1239 name = ast_strdupa(ast_channel_name(chan)); \
1240 if (ast_channel_tech(chan)->get_pvt_uniqueid) { \
1241 pvtid = ast_strdupa(ast_channel_tech(chan)->get_pvt_uniqueid(chan)); \
1245 ast_channel_lock(c1);
1246 UPDATE_BRIDGE_VARS_GET(c1, c1_name, c1_pvtid);
1247 ast_channel_unlock(c1);
1249 ast_channel_lock(c0);
1251 UPDATE_BRIDGE_VARS_GET(c0, c0_name, c0_pvtid);
1252 ast_channel_unlock(c0);
1254 ast_channel_lock(c1);
1256 ast_channel_unlock(c1);
1269 static void fill_bridgepeer_buf(
char *buf,
unsigned int cur_idx,
const char *names[],
unsigned int num_names)
1271 int need_separator = 0;
1277 for (idx = 0; idx < num_names; ++idx) {
1278 if (idx == cur_idx) {
1282 if (need_separator) {
1306 static void set_bridge_peer_vars_multiparty(
struct ast_bridge *bridge)
1313 #define MAX_BRIDGEPEER_CHANS (10 + 1)
1316 unsigned int num_names;
1323 num_names = MIN(bridge->
num_channels, MAX_BRIDGEPEER_CHANS);
1324 names =
ast_alloca(num_names *
sizeof(*names));
1327 if (num_names <= idx) {
1330 ast_channel_lock(bridge_channel->
chan);
1332 ast_channel_unlock(bridge_channel->
chan);
1337 for (idx = 0; idx < num_names; ++idx) {
1338 len += strlen(names[idx]);
1346 if (idx < num_names) {
1347 fill_bridgepeer_buf(buf, idx, names, num_names);
1351 ast_channel_lock(bridge_channel->
chan);
1353 ast_channel_unlock(bridge_channel->
chan);
1366 static void set_bridge_peer_vars_holding(
struct ast_bridge *bridge)
1371 ast_channel_lock(bridge_channel->
chan);
1373 ast_channel_unlock(bridge_channel->
chan);
1386 static void set_bridge_peer_vars(
struct ast_bridge *bridge)
1389 set_bridge_peer_vars_holding(bridge);
1399 set_bridge_peer_vars_multiparty(bridge);
1403 void bridge_reconfigured(
struct ast_bridge *bridge,
unsigned int colp_update)
1410 && smart_bridge_operation(bridge)) {
1412 bridge_dissolve(bridge, 0);
1415 bridge_complete_join(bridge);
1420 check_bridge_play_sounds(bridge);
1421 set_bridge_peer_vars(bridge);
1425 bridge_reconfigured_connected_line_update(bridge);
1434 if (bridge_channel->
chan == chan) {
1439 return bridge_channel;
1448 ast_channel_lock(chan);
1450 ast_channel_unlock(chan);
1451 if (!bridge_channel) {
1457 bridge = bridge_channel->
bridge;
1458 if (bridge_channel == bridge_find_channel(bridge, chan)) {
1466 bridge_reconfigured(bridge, 1);
1500 ast_mutex_lock(&cond->
lock);
1502 ast_cond_signal(&cond->
cond);
1503 ast_mutex_unlock(&cond->
lock);
1508 static void bridge_channel_impart_ds_head_dtor(
void *doomed)
1510 bridge_channel_impart_ds_head_signal(doomed);
1523 static void bridge_channel_impart_ds_head_fixup(
void *data,
struct ast_channel *old_chan,
struct ast_channel *new_chan)
1529 bridge_channel_impart_ds_head_signal(data);
1533 .
type =
"bridge-impart-ds",
1534 .destroy = bridge_channel_impart_ds_head_dtor,
1535 .chan_fixup = bridge_channel_impart_ds_head_fixup,
1554 ast_channel_lock(chan);
1558 datastore = ast_datastore_alloc(&bridge_channel_impart_ds_info, NULL);
1560 ast_channel_unlock(chan);
1565 ast_channel_unlock(chan);
1569 datastore->
data = ds_head;
1572 ds_head = datastore->
data;
1573 ast_assert(ds_head != NULL);
1578 ast_channel_unlock(chan);
1582 void bridge_channel_impart_signal(
struct ast_channel *chan)
1586 ast_channel_lock(chan);
1589 bridge_channel_impart_ds_head_signal(datastore->
data);
1591 ast_channel_unlock(chan);
1603 ast_mutex_lock(&cond->
lock);
1604 while (!cond->
done) {
1605 ast_cond_wait(&cond->
cond, &cond->
lock);
1607 ast_mutex_unlock(&cond->
lock);
1630 SCOPE_TRACE(1,
"%s Bridge: %s\n", ast_channel_name(chan), bridge->
uniqueid);
1632 bridge_channel = bridge_channel_internal_alloc(bridge);
1636 if (!bridge_channel) {
1637 ao2_t_cleanup(swap,
"Error exit: bridge_channel alloc failed");
1642 ast_assert(features != NULL);
1645 ao2_t_cleanup(swap,
"Error exit: features is NULL");
1653 ast_channel_lock(chan);
1657 ast_channel_internal_bridge_channel_set(chan, bridge_channel);
1659 ast_channel_unlock(chan);
1660 bridge_channel->
thread = pthread_self();
1671 if (bridge_channel->
swap) {
1672 bcswap = bridge_find_channel(bridge, bridge_channel->
swap);
1679 res = bridge_channel_internal_join(bridge_channel);
1683 ast_channel_lock(chan);
1684 ast_channel_internal_bridge_channel_set(chan, NULL);
1685 ast_channel_unlock(chan);
1687 ao2_lock(bridge_channel);
1688 bridge_channel->
chan = NULL;
1689 ao2_unlock(bridge_channel);
1691 ao2_t_cleanup(bridge_channel->
swap,
"Bridge complete: join failed");
1692 bridge_channel->
swap = NULL;
1699 bridge_channel_impart_signal(chan);
1703 ast_channel_lock(chan);
1705 ast_channel_unlock(chan);
1716 if (bridge_channel->
callid) {
1720 res = bridge_channel_internal_join(bridge_channel);
1727 ao2_t_cleanup(bridge_channel->
swap,
"Bridge complete: Departable impart join failed");
1728 bridge_channel->
swap = NULL;
1735 bridge_channel_impart_signal(bridge_channel->
chan);
1747 if (bridge_channel->
callid) {
1751 bridge_channel_internal_join(bridge_channel);
1752 chan = bridge_channel->
chan;
1755 ast_channel_lock(chan);
1756 ast_channel_internal_bridge_channel_set(chan, NULL);
1757 ast_channel_unlock(chan);
1759 ao2_lock(bridge_channel);
1760 bridge_channel->
chan = NULL;
1761 ao2_unlock(bridge_channel);
1763 ao2_t_cleanup(bridge_channel->
swap,
"Bridge complete: Independent impart join failed");
1764 bridge_channel->
swap = NULL;
1772 bridge_channel_impart_signal(chan);
1777 static int bridge_impart_internal(
struct ast_bridge *bridge,
1788 if (ast_channel_pbx(chan)) {
1789 ast_log(AST_LOG_WARNING,
"Channel %s has a PBX thread and cannot be imparted into bridge %s\n",
1790 ast_channel_name(chan), bridge->
uniqueid);
1804 bridge_channel = bridge_channel_internal_alloc(bridge);
1805 if (!bridge_channel) {
1810 ast_channel_lock(chan);
1812 ast_log(AST_LOG_NOTICE,
"Channel %s is a zombie and cannot be imparted into bridge %s\n",
1813 ast_channel_name(chan), bridge->
uniqueid);
1816 ast_channel_internal_bridge_channel_set(chan, bridge_channel);
1818 ast_channel_unlock(chan);
1820 bridge_channel->
swap = ao2_t_bump(swap,
"Setting up bridge impart");
1832 if (bridge_channel->
swap) {
1833 bcswap = bridge_find_channel(bridge, bridge_channel->
swap);
1841 res = bridge_channel_impart_add(chan, cond);
1845 res = ast_pthread_create_detached(&bridge_channel->
thread, NULL,
1848 res = ast_pthread_create(&bridge_channel->
thread, NULL,
1853 bridge_channel_impart_wait(cond);
1859 ast_channel_lock(chan);
1860 ast_channel_internal_bridge_channel_set(chan, NULL);
1861 ast_channel_unlock(chan);
1863 ao2_lock(bridge_channel);
1864 bridge_channel->
chan = NULL;
1865 ao2_unlock(bridge_channel);
1866 ao2_t_cleanup(bridge_channel->
swap,
"Bridge complete: Impart failed");
1867 bridge_channel->
swap = NULL;
1888 SCOPE_TRACE(1,
"%s Bridge: %s\n", ast_channel_name(chan), bridge->
uniqueid);
1890 ast_mutex_init(&cond.
lock);
1891 ast_cond_init(&cond.
cond, NULL);
1893 res = bridge_impart_internal(bridge, chan, swap, features, flags, &cond);
1897 bridge_channel_impart_signal(chan);
1900 ast_cond_destroy(&cond.
cond);
1901 ast_mutex_destroy(&cond.
lock);
1910 SCOPE_TRACE(1,
"%s\n", ast_channel_name(chan));
1912 ast_channel_lock(chan);
1913 bridge_channel = ast_channel_internal_bridge_channel(chan);
1914 departable = bridge_channel && bridge_channel->
depart_wait;
1915 ast_channel_unlock(chan);
1917 ast_log(LOG_ERROR,
"Channel %s cannot be departed.\n",
1918 ast_channel_name(chan));
1938 ast_debug(1,
"Waiting for %p(%s) bridge thread to die.\n",
1939 bridge_channel, ast_channel_name(bridge_channel->
chan));
1940 pthread_join(bridge_channel->
thread, NULL);
1942 ast_channel_lock(chan);
1943 ast_channel_internal_bridge_channel_set(chan, NULL);
1944 ast_channel_unlock(chan);
1955 ast_debug(1,
"Removing channel %s from bridge %s\n",
1956 ast_channel_name(chan), bridge->
uniqueid);
1961 if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
1974 static void kick_it(
struct ast_bridge_channel *bridge_channel,
const void *payload,
size_t payload_size)
1987 if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
2013 ast_channel_lock(bridge_channel->
chan);
2014 old_bridge = bridge_channel->
bridge;
2015 bridge_channel->
bridge = new_bridge;
2017 ast_channel_unlock(bridge_channel->
chan);
2030 for (; (hook = ao2_iterator_next(&iter));
ao2_ref(hook, -1)) {
2034 if (hook->
type != AST_BRIDGE_HOOK_TYPE_MOVE) {
2038 remove_me = move_cb(bridge_channel, hook->
hook_pvt, src, dst);
2040 ast_debug(1,
"Move detection hook %p is being removed from %p(%s)\n",
2041 hook, bridge_channel, ast_channel_name(bridge_channel->
chan));
2049 unsigned int optimized)
2054 ast_debug(1,
"Merging bridge %s into bridge %s\n",
2079 for (idx = 0; idx < num_kick; ++idx) {
2080 if (bridge_channel == kick_me[idx]) {
2087 bridge_channel_internal_pull(bridge_channel);
2096 bridge_channel_moving(bridge_channel, bridge_channel->
bridge, dst_bridge);
2099 bridge_channel_change_bridge(bridge_channel, dst_bridge);
2101 if (bridge_channel_internal_push(bridge_channel)) {
2115 for (idx = 0; idx < num_kick; ++idx) {
2116 bridge_channel = kick_me[idx];
2121 bridge_channel_internal_pull(bridge_channel);
2127 bridge_reconfigured(dst_bridge, !optimized);
2128 bridge_reconfigured(src_bridge, !optimized);
2130 ast_debug(1,
"Merged bridge %s into bridge %s\n",
2156 int bridge1_priority;
2157 int bridge2_priority;
2159 if (!ast_test_flag(&bridge1->feature_flags,
2161 && !ast_test_flag(&bridge2->feature_flags,
2167 bridge1_priority = bridge1->v_table->get_merge_priority(bridge1);
2168 bridge2_priority = bridge2->v_table->get_merge_priority(bridge2);
2169 if (bridge2_priority < bridge1_priority) {
2170 merge.
dest = bridge1;
2171 merge.
src = bridge2;
2172 }
else if (bridge1_priority < bridge2_priority) {
2173 merge.
dest = bridge2;
2174 merge.
src = bridge1;
2177 if (bridge2->num_channels <= bridge1->num_channels) {
2178 merge.
dest = bridge1;
2179 merge.
src = bridge2;
2181 merge.
dest = bridge2;
2182 merge.
src = bridge1;
2188 merge.
dest = bridge1;
2189 merge.
src = bridge2;
2193 merge.
dest = bridge2;
2194 merge.
src = bridge1;
2216 static int bridge_merge_locked(
struct ast_bridge *dst_bridge,
struct ast_bridge *src_bridge,
int merge_best_direction,
struct ast_channel **kick_me,
unsigned int num_kick)
2222 ast_assert(dst_bridge && src_bridge && dst_bridge != src_bridge && (!num_kick || kick_me));
2225 ast_debug(1,
"Can't merge bridges %s and %s, at least one bridge is dissolved.\n",
2231 ast_debug(1,
"Can't merge bridges %s and %s, masquerade only.\n",
2236 ast_debug(1,
"Can't merge bridges %s and %s, merging temporarily inhibited.\n",
2241 if (merge_best_direction) {
2242 merge = bridge_merge_determine_direction(dst_bridge, src_bridge);
2244 merge.
dest = dst_bridge;
2245 merge.
src = src_bridge;
2251 ast_debug(1,
"Can't merge bridges %s and %s, merging inhibited.\n",
2261 ast_debug(1,
"Can't merge bridge %s into bridge %s, not enough channels in source bridge.\n",
2269 ast_debug(1,
"Can't merge bridge %s into bridge %s, multimix is needed and it cannot be acquired.\n",
2275 unsigned int num_to_kick = 0;
2278 kick_them =
ast_alloca(num_kick *
sizeof(*kick_them));
2279 for (idx = 0; idx < num_kick; ++idx) {
2280 kick_them[num_to_kick] = bridge_find_channel(merge.
src, kick_me[idx]);
2281 if (!kick_them[num_to_kick]) {
2282 kick_them[num_to_kick] = bridge_find_channel(merge.
dest, kick_me[idx]);
2284 if (kick_them[num_to_kick]) {
2289 if (num_to_kick != num_kick) {
2290 ast_debug(1,
"Can't merge bridge %s into bridge %s, at least one kicked channel is not in either bridge.\n",
2296 bridge_do_merge(merge.
dest, merge.
src, kick_them, num_kick, 0);
2305 ast_assert(dst_bridge && src_bridge);
2308 res = bridge_merge_locked(dst_bridge, src_bridge, merge_best_direction, kick_me, num_kick);
2315 unsigned int optimized)
2321 if (bridge_channel->
swap) {
2322 ast_debug(1,
"Moving %p(%s) into bridge %s swapping with %s\n",
2323 bridge_channel, ast_channel_name(bridge_channel->
chan), dst_bridge->
uniqueid,
2324 ast_channel_name(bridge_channel->
swap));
2326 ast_debug(1,
"Moving %p(%s) into bridge %s\n",
2327 bridge_channel, ast_channel_name(bridge_channel->
chan), dst_bridge->
uniqueid);
2330 orig_bridge = bridge_channel->
bridge;
2331 was_in_bridge = bridge_channel->
in_bridge;
2333 bridge_channel_internal_pull(bridge_channel);
2342 bridge_channel->
swap = NULL;
2343 bridge_reconfigured(orig_bridge, 0);
2349 bridge_channel_change_bridge(bridge_channel, dst_bridge);
2351 bridge_channel_moving(bridge_channel, orig_bridge, dst_bridge);
2353 if (bridge_channel_internal_push_full(bridge_channel, optimized)) {
2357 if (attempt_recovery && was_in_bridge) {
2359 bridge_channel_change_bridge(bridge_channel, orig_bridge);
2361 if (bridge_channel_internal_push(bridge_channel)) {
2370 bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
2373 }
else if (!optimized) {
2374 bridge_channel_settle_owed_events(orig_bridge, bridge_channel);
2377 bridge_reconfigured(dst_bridge, !optimized);
2378 bridge_reconfigured(orig_bridge, !optimized);
2404 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, at least one bridge is dissolved.\n",
2410 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, masquerade only.\n",
2415 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, temporarily inhibited.\n",
2420 bridge_channel = bridge_find_channel(src_bridge, chan);
2421 if (!bridge_channel) {
2422 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, channel not in bridge.\n",
2427 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, channel leaving bridge.\n",
2433 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, channel immovable.\n",
2441 bridge_channel_swap = bridge_find_channel(dst_bridge, swap);
2442 if (!bridge_channel_swap) {
2443 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, swap channel %s not in bridge.\n",
2445 ast_channel_name(swap));
2449 ast_debug(1,
"Can't move channel %s from bridge %s into bridge %s, swap channel %s leaving bridge.\n",
2451 ast_channel_name(swap));
2457 return bridge_do_move(dst_bridge, bridge_channel, attempt_recovery, 0);
2465 res = bridge_move_locked(dst_bridge, src_bridge, chan, swap, attempt_recovery);
2479 ast_channel_lock(chan);
2481 ast_channel_unlock(chan);
2490 bridge_channel = bridge_find_channel(chan_bridge, chan);
2492 if (bridge_move_locked(bridge, chan_bridge, chan, NULL, 1)) {
2502 ast_assert(bridge_channel != NULL);
2508 bridge_dissolve_check_stolen(chan_bridge, bridge_channel);
2517 ast_log(LOG_WARNING,
"Could not gain control of channel %s\n", ast_channel_name(chan));
2533 if (ast_channel_pbx(yanked_chan)) {
2542 if (play_tone && !ast_strlen_zero(xfersound)) {
2543 struct ast_channel *play_chan = yanked_chan ?: chan;
2546 ast_channel_lock(play_chan);
2548 ast_channel_unlock(play_chan);
2550 if (!play_bridge_channel) {
2551 ast_log(LOG_WARNING,
"Unable to play tone for channel %s. No longer in a bridge.\n",
2552 ast_channel_name(play_chan));
2560 static int bridge_allows_optimization(
struct ast_bridge *bridge)
2594 bridge_channel = ast_channel_internal_bridge_channel(chan);
2598 bridge = bridge_channel->
bridge;
2605 if (!bridge_channel_internal_allows_optimization(bridge_channel) ||
2606 !bridge_allows_optimization(bridge)) {
2629 if (ast_channel_trylock(peer)) {
2633 ast_channel_unlock(peer);
2637 ast_channel_unlock(peer);
2642 ast_channel_unlock(peer);
2645 bridge_channel = ast_channel_internal_bridge_channel(peer);
2647 ast_channel_unlock(peer);
2650 bridge = bridge_channel->
bridge;
2655 ast_channel_unlock(peer);
2658 if (!bridge_allows_optimization(bridge) ||
2659 !bridge_channel_internal_allows_optimization(bridge_channel)) {
2662 ast_channel_unlock(peer);
2708 && chan_priority <= peer_priority) {
2711 && peer_priority <= chan_priority) {
2745 static int try_swap_optimize_out(
struct ast_bridge *chan_bridge,
2756 switch (bridges_allow_swap_optimization(chan_bridge, peer_bridge)) {
2758 dst_bridge = chan_bridge;
2759 dst_bridge_channel = chan_bridge_channel;
2760 src_bridge_channel = peer_bridge_channel;
2763 dst_bridge = peer_bridge;
2764 dst_bridge_channel = peer_bridge_channel;
2765 src_bridge_channel = chan_bridge_channel;
2776 if (ast_channel_trylock(other->
chan)) {
2782 ast_verb(4,
"Move-swap optimizing %s <-- %s.\n",
2783 ast_channel_name(dst_bridge_channel->
chan),
2784 ast_channel_name(other->
chan));
2789 dst_bridge_channel->
chan == pvt->
owner ? AST_UNREAL_OWNER : AST_UNREAL_CHAN,
2793 other->
swap = dst_bridge_channel->
chan;
2794 if (!bridge_do_move(dst_bridge, other, 1, 1)) {
2802 ast_channel_unlock(other->
chan);
2838 *merge = bridge_merge_determine_direction(chan_bridge, peer_bridge);
2869 static int try_merge_optimize_out(
struct ast_bridge *chan_bridge,
2876 chan_bridge_channel,
2877 peer_bridge_channel,
2881 switch (bridges_allow_merge_optimization(chan_bridge, peer_bridge, ARRAY_LEN(kick_me), &merge)) {
2887 ast_debug(4,
"Can't optimize %s -- %s out, not enough channels in bridge %s.\n",
2888 ast_channel_name(chan_bridge_channel->
chan),
2889 ast_channel_name(peer_bridge_channel->
chan),
2893 ast_debug(4,
"Can't optimize %s -- %s out, multimix is needed and it cannot be acquired.\n",
2894 ast_channel_name(chan_bridge_channel->
chan),
2895 ast_channel_name(peer_bridge_channel->
chan));
2899 ast_verb(4,
"Merge optimizing %s -- %s out.\n",
2900 ast_channel_name(chan_bridge_channel->
chan),
2901 ast_channel_name(peer_bridge_channel->
chan));
2908 merge.
dest == ast_channel_internal_bridge(pvt->
owner) ? AST_UNREAL_OWNER : AST_UNREAL_CHAN,
2912 bridge_do_merge(merge.
dest, merge.
src, kick_me, ARRAY_LEN(kick_me), 1);
2928 chan_bridge = optimize_lock_chan_stack(chan);
2932 chan_bridge_channel = ast_channel_internal_bridge_channel(chan);
2934 peer_bridge = optimize_lock_peer_stack(peer);
2936 peer_bridge_channel = ast_channel_internal_bridge_channel(peer);
2938 res = try_swap_optimize_out(chan_bridge, chan_bridge_channel,
2939 peer_bridge, peer_bridge_channel, pvt);
2941 res = try_merge_optimize_out(chan_bridge, chan_bridge_channel,
2942 peer_bridge, peer_bridge_channel, pvt);
2943 }
else if (0 < res) {
2950 ast_channel_unlock(peer);
2965 if (!bridge_allows_optimization(chan_bridge) || !bridge_allows_optimization(peer_bridge)) {
2969 switch (bridges_allow_swap_optimization(chan_bridge, peer_bridge)) {
2980 if (bridges_allow_merge_optimization(chan_bridge, peer_bridge, 2, &merge) !=
MERGE_ALLOWED) {
2984 if (merge.
dest == chan_bridge) {
2991 void bridge_merge_inhibit_nolock(
struct ast_bridge *bridge,
int request)
2996 ast_assert(0 <= new_request);
3003 bridge_merge_inhibit_nolock(bridge, request);
3016 if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
3021 bridge_channel_internal_suspend_nolock(bridge_channel);
3035 if (!(bridge_channel = bridge_find_channel(bridge, chan))) {
3040 bridge_channel_internal_unsuspend_nolock(bridge_channel);
3069 if (!ast_strlen_zero(dtmf)) {
3102 callback(bridge_channel, hook_pvt);
3139 static void bridge_hook_destroy(
void *vhook)
3194 hook_pvt, destructor, remove_flags);
3242 hook = bridge_hook_generic(
sizeof(*hook), callback, hook_pvt, destructor,
3271 return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
3272 AST_BRIDGE_HOOK_TYPE_HANGUP);
3281 return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
3282 AST_BRIDGE_HOOK_TYPE_JOIN);
3291 return bridge_other_hook(features, callback, hook_pvt, destructor, remove_flags,
3292 AST_BRIDGE_HOOK_TYPE_LEAVE);
3303 return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags,
3304 AST_BRIDGE_HOOK_TYPE_TALK);
3315 return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags,
3316 AST_BRIDGE_HOOK_TYPE_MOVE);
3321 unsigned int interval,
3330 if (!features ||!interval || !callback) {
3336 hook_pvt, destructor, remove_flags);
3346 ast_debug(1,
"Putting interval hook %p with interval %u in the heap on features %p\n",
3362 return res ? -1 : 0;
3378 if (ast_strlen_zero(dtmf)) {
3381 if (ast_strlen_zero(dtmf)) {
3382 ast_debug(1,
"Failed to enable built in feature %u on %p, no DTMF string is available for it.\n",
3393 config, destructor, remove_flags);
3398 memset(limits, 0,
sizeof(*limits));
3420 return callback(features, limits, remove_flags);
3423 ast_log(LOG_ERROR,
"Attempted to set limits without an AST_BRIDGE_BUILTIN_INTERVAL_LIMITS callback registered.\n");
3445 static int hook_remove_match(
void *obj,
void *arg,
int flags)
3450 if (ast_test_flag(&hook->
remove_flags, *remove_flags)) {
3468 hook_remove_match, &remove_flags);
3484 ast_heap_wrlock(hooks);
3491 if (ast_test_flag(&hook->
remove_flags, remove_flags)) {
3498 ast_heap_unlock(hooks);
3503 hooks_remove_container(features->
dtmf_hooks, remove_flags);
3504 hooks_remove_container(features->
other_hooks, remove_flags);
3508 static int interval_hook_time_cmp(
void *a,
void *b)
3539 static int bridge_dtmf_hook_sort(
const void *obj_left,
const void *obj_right,
int flags)
3543 const char *right_key = obj_right;
3552 cmp = strcasecmp(hook_left->
dtmf.
code, right_key);
3555 cmp = strncasecmp(hook_left->
dtmf.
code, right_key, strlen(right_key));
3623 memset(features, 0,
sizeof(*features));
3726 static void cleanup_video_mode(
struct ast_bridge *bridge)
3752 cleanup_video_mode(bridge);
3754 if (video_src_chan) {
3756 ast_verb(5,
"Video source in bridge '%s' (%s) is now '%s' (%s)\n",
3758 ast_channel_name(video_src_chan),
3759 ast_channel_uniqueid(video_src_chan));
3769 cleanup_video_mode(bridge);
3777 cleanup_video_mode(bridge);
3829 data->average_talking_energy = talker_energy;
3830 }
else if ((data->average_talking_energy < talker_energy) && is_keyframe) {
3839 data->average_talking_energy = talker_energy;
3840 ast_verb(5,
"Video source in bridge '%s' (%s) is now '%s' (%s)\n",
3846 }
else if ((data->average_talking_energy < talker_energy) && !is_keyframe) {
3848 }
else if (!data->
chan_vsrc && is_keyframe) {
3850 data->average_talking_energy = talker_energy;
3851 ast_verb(5,
"Video source in bridge '%s' (%s) is now '%s' (%s)\n",
3937 bridge->
softmix.
video_mode.mode_data.talker_src_data.average_talking_energy = 0;
3953 switch (video_mode) {
3973 static int channel_hash(
const void *obj,
int flags)
3976 const char *
name = obj;
3982 name = ast_channel_name(chan);
3996 static int channel_cmp(
void *obj,
void *arg,
int flags)
4000 const char *right_name = arg;
4006 right_name = ast_channel_name(right);
4009 cmp = strcmp(ast_channel_name(left), right_name);
4012 cmp = strncmp(ast_channel_name(left), right_name, strlen(right_name));
4024 13, channel_hash, NULL, channel_cmp);
4059 if (iter->
chan != chan) {
4065 if (in_bridge && peer) {
4123 ast_channel_lock(transferer);
4124 caps =
ao2_bump(ast_channel_nativeformats(transferer));
4125 ast_channel_unlock(transferer);
4127 snprintf(chan_name,
sizeof(chan_name),
"%s@%s", exten, context);
4128 local =
ast_request(
"Local", caps, NULL, transferer,
4147 ast_channel_unlock(local);
4148 ast_channel_unlock(transferer);
4150 if (new_channel_cb) {
4154 if (
ast_call(local, chan_name, 0)) {
4188 (transferee = ao2_iterator_next(&channel_iter));
4189 ao2_cleanup(transferee)) {
4190 if (transferee != transferer) {
4225 #define BRIDGE_LOCK_ONE_OR_BOTH(b1, b2) \
4228 ast_bridge_lock_both(b1, b2); \
4230 ast_bridge_lock(b1); \
4234 static const char *dest =
"_attended@transfer/m";
4238 const char *app = NULL;
4241 ast_channel_lock(chan1);
4242 caps =
ao2_bump(ast_channel_nativeformats(chan1));
4243 ast_channel_unlock(chan1);
4245 local_chan =
ast_request(
"Local", caps, NULL, chan1, dest, &cause);
4256 ast_channel_unlock(local_chan);
4257 ast_channel_unlock(chan1);
4280 if (
ast_call(local_chan, dest, 0)) {
4282 BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
4291 ao2_cleanup(local_chan);
4292 BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
4295 BRIDGE_LOCK_ONE_OR_BOTH(bridge1, bridge2);
4303 if (!locals[0] || !locals[1]) {
4304 ast_log(LOG_ERROR,
"Transfer failed probably due to an early hangup - "
4305 "missing other half of '%s'\n", ast_channel_name(local_chan));
4307 ao2_cleanup(local_chan);
4312 if (local_chan != locals[0]) {
4313 SWAP(locals[0], locals[1]);
4322 ao2_cleanup(local_chan);
4336 ast_channel_lock(transferer);
4338 ast_channel_unlock(transferer);
4340 if (!transferer_bridge_channel) {
4345 context, exten, new_channel_cb, user_data_wrapper)) {
4358 writevar = ATTENDEDTRANSFER;
4359 erasevar = BLINDTRANSFER;
4361 writevar = BLINDTRANSFER;
4362 erasevar = ATTENDEDTRANSFER;
4383 static void set_transfer_variables_all(
struct ast_channel *transferer,
struct ao2_container *channels,
int is_attended)
4387 const char *transferer_name;
4388 const char *transferer_bridgepeer;
4390 ast_channel_lock(transferer);
4391 transferer_name =
ast_strdupa(ast_channel_name(transferer));
4393 ast_channel_unlock(transferer);
4396 (chan = ao2_iterator_next(&iter));
4397 ao2_cleanup(chan)) {
4398 if (chan == transferer) {
4412 ast_channel_lock(chan);
4414 ast_channel_unlock(chan);
4426 struct ast_channel *transferer,
const char *exten,
const char *context,
4435 int do_bridge_transfer;
4436 int transfer_prohibited;
4440 if (!transfer_message) {
4444 ast_log(LOG_ERROR,
"Unable to allocate memory for blind transfer publication from %s\n",
4445 ast_channel_name(transferer));
4458 if (!transfer_message->
bridge) {
4472 ast_channel_lock(transferer);
4474 ast_channel_unlock(transferer);
4475 if (!bridge_channel) {
4480 user_data_wrapper = ao2_alloc(
sizeof(*user_data_wrapper), NULL);
4481 if (!user_data_wrapper) {
4486 user_data_wrapper->data = user_data;
4491 transfer_result = try_parking(transferer, context, exten, new_channel_cb, user_data_wrapper);
4518 if (transfer_prohibited) {
4523 set_transfer_variables_all(transferer, channels, 0);
4525 if (do_bridge_transfer) {
4526 transfer_result = blind_transfer_bridge(is_external, transferer, bridge,
4527 exten, context, transferee, new_channel_cb, user_data_wrapper, transfer_message);
4538 if (bridge_channel_internal_queue_blind_transfer(transferee, exten, context,
4539 new_channel_cb, user_data_wrapper)) {
4548 transfer_message->
result = transfer_result;
4550 return transfer_result;
4574 if (bridged_to_source
4578 bridged_to_source->
swap = swap_channel;
4579 if (bridge_do_move(dest_bridge, bridged_to_source, 1, 0)) {
4619 to_transferee_bridge_channel,
4620 to_target_bridge_channel,
4633 set_transfer_variables_all(to_transferee, channels, 1);
4637 final_bridge = to_transferee_bridge;
4638 res = bridge_swap_attended_transfer(to_transferee_bridge, to_target_bridge_channel, to_transferee);
4641 final_bridge = to_target_bridge;
4642 res = bridge_swap_attended_transfer(to_target_bridge, to_transferee_bridge_channel, to_transfer_target);
4645 final_bridge = to_transferee_bridge;
4646 bridge_do_merge(to_transferee_bridge, to_target_bridge, kick_me, ARRAY_LEN(kick_me), 0);
4650 final_bridge = to_target_bridge;
4651 bridge_do_merge(to_target_bridge, to_transferee_bridge, kick_me, ARRAY_LEN(kick_me), 0);
4666 to_transferee_bridge, to_target_bridge, transfer_msg);
4690 int transfer_prohibited;
4691 int do_bridge_transfer;
4693 const char *app = NULL;
4694 int hangup_target = 0;
4700 to_transfer_target, to_target_bridge, NULL, NULL);
4701 if (!transfer_msg) {
4702 ast_log(LOG_ERROR,
"Unable to create Stasis publication for attended transfer from %s\n",
4703 ast_channel_name(to_transferee));
4708 if (!to_transferee_bridge && !to_target_bridge) {
4713 ast_channel_lock(to_transferee);
4715 ast_channel_unlock(to_transferee);
4717 ast_channel_lock(to_transfer_target);
4719 ast_channel_unlock(to_transfer_target);
4721 if (to_transferee_bridge_channel) {
4724 ast_log(LOG_ERROR,
"Transferee channel disappeared during transfer!\n");
4730 if (to_target_bridge_channel) {
4731 const char *target_complete_sound;
4735 ast_log(LOG_ERROR,
"Target channel disappeared during transfer!\n");
4741 ast_channel_lock(to_transfer_target);
4743 "ATTENDED_TRANSFER_COMPLETE_SOUND");
4744 if (!ast_strlen_zero(target_complete_sound)) {
4745 target_complete_sound =
ast_strdupa(target_complete_sound);
4747 target_complete_sound = NULL;
4749 ast_channel_unlock(to_transfer_target);
4750 if (!target_complete_sound) {
4751 ast_channel_lock(to_transferee);
4753 "ATTENDED_TRANSFER_COMPLETE_SOUND");
4754 if (!ast_strlen_zero(target_complete_sound)) {
4755 target_complete_sound =
ast_strdupa(target_complete_sound);
4757 target_complete_sound = NULL;
4759 ast_channel_unlock(to_transferee);
4761 if (target_complete_sound) {
4763 target_complete_sound, NULL);
4768 if (to_transferee_bridge && to_target_bridge) {
4770 if (!to_transferee_bridge_channel || !to_target_bridge_channel) {
4776 res = two_bridge_attended_transfer(to_transferee, to_transferee_bridge_channel,
4777 to_transfer_target, to_target_bridge_channel,
4778 to_transferee_bridge, to_target_bridge, transfer_msg);
4786 the_bridge = to_transferee_bridge ?: to_target_bridge;
4787 chan_bridged = to_transferee_bridge ? to_transferee : to_transfer_target;
4788 chan_unbridged = to_transferee_bridge ? to_transfer_target : to_transferee;
4794 app =
ast_strdupa(ast_channel_appl(chan_unbridged) ?:
"unknown");
4806 if (chan_count <= 1) {
4810 transfer_prohibited = ast_test_flag(&the_bridge->
feature_flags,
4812 do_bridge_transfer = ast_test_flag(&the_bridge->
feature_flags,
4817 if (transfer_prohibited) {
4822 set_transfer_variables_all(to_transferee, channels, 1);
4824 if (do_bridge_transfer) {
4829 hangup_target = chan_bridged == to_transfer_target;
4836 transferee = get_transferee(channels, chan_bridged);
4842 if (bridge_channel_internal_queue_attended_transfer(transferee, chan_unbridged)) {
4857 transfer_msg->
result = res;
4869 static void bridge_manager_service(
struct ast_bridge *bridge)
4877 bridge_handle_actions(bridge);
4886 static void *bridge_manager_thread(
void *data)
4892 while (!manager->
stop) {
4898 ao2_unlock(manager);
4901 bridge_manager_service(request->
bridge);
4907 ao2_unlock(manager);
4919 static void bridge_manager_destroy(
void *obj)
4924 if (manager->
thread != AST_PTHREADT_NULL) {
4928 ast_cond_signal(&manager->
cond);
4929 ao2_unlock(manager);
4930 ast_debug(1,
"Waiting for bridge manager thread to die.\n");
4931 pthread_join(manager->
thread, NULL);
4940 ast_cond_destroy(&manager->
cond);
4955 manager = ao2_alloc(
sizeof(*manager), bridge_manager_destroy);
4960 ast_cond_init(&manager->
cond, NULL);
4964 if (ast_pthread_create(&manager->
thread, NULL, bridge_manager_thread, manager)) {
4966 manager->
thread = AST_PTHREADT_NULL;
4990 static int bridge_sort_cmp(
const void *obj_left,
const void *obj_right,
int flags)
4992 const struct ast_bridge *bridge_left = obj_left;
4993 const struct ast_bridge *bridge_right = obj_right;
4994 const char *right_key = obj_right;
5000 right_key = bridge_right->
uniqueid;
5003 cmp = strcmp(bridge_left->
uniqueid, right_key);
5006 cmp = strncmp(bridge_left->
uniqueid, right_key, strlen(right_key));
5017 static int complete_bridge_live_search(
void *obj,
void *arg,
int flags)
5028 static char *complete_bridge_live(
const char *word)
5031 complete_bridge_live_search, (
char *) word);
5038 #define FORMAT_HDR "%-36s %5s %-15s %-15s %s\n"
5039 #define FORMAT_ROW "%-36s %5u %-15s %-15s %s\n"
5046 e->
command =
"bridge show all";
5048 "Usage: bridge show all\n"
5049 " List all bridges\n";
5055 ast_cli(a->fd, FORMAT_HDR,
"Bridge-ID",
"Chans",
"Type",
"Technology",
"Duration");
5058 for (; (bridge = ao2_iterator_next(&iter));
ao2_ref(bridge, -1)) {
5060 char print_time[32];
5064 ast_cli(a->fd, FORMAT_ROW,
5093 ast_cli(a->fd,
"Channel: %s\n", snapshot->
base->
name);
5102 char print_time[32];
5108 "Usage: bridge show <bridge-id>\n"
5109 " Show information about the <bridge-id> bridge\n";
5113 return complete_bridge_live(a->word);
5119 return CLI_SHOWUSAGE;
5124 ast_cli(a->fd,
"Bridge '%s' not found\n", a->argv[2]);
5130 ast_cli(a->fd,
"Id: %s\n", snapshot->
uniqueid);
5131 ast_cli(a->fd,
"Type: %s\n",
S_OR(snapshot->
subclass,
"<unknown>"));
5132 ast_cli(a->fd,
"Technology: %s\n",
S_OR(snapshot->
technology,
"<unknown>"));
5133 ast_cli(a->fd,
"Subclass: %s\n", snapshot->
subclass);
5134 ast_cli(a->fd,
"Creator: %s\n", snapshot->
creator);
5135 ast_cli(a->fd,
"Name: %s\n", snapshot->
name);
5138 ast_cli(a->fd,
"Num-Channels: %u\n", snapshot->
num_channels);
5139 ast_cli(a->fd,
"Num-Active: %u\n", snapshot->
num_active);
5140 ast_cli(a->fd,
"Duration: %s\n", print_time);
5154 e->
command =
"bridge destroy";
5156 "Usage: bridge destroy <bridge-id>\n"
5157 " Destroy the <bridge-id> bridge\n";
5161 return complete_bridge_live(a->word);
5167 return CLI_SHOWUSAGE;
5172 ast_cli(a->fd,
"Bridge '%s' not found\n", a->argv[2]);
5176 ast_cli(a->fd,
"Destroying bridge '%s'\n", a->argv[2]);
5183 static char *complete_bridge_participant(
const char *bridge_name,
const char *word)
5194 wordlen = strlen(word);
5198 if (!strncasecmp(ast_channel_name(bridge_channel->
chan), word, wordlen)) {
5213 static const char *
const completions[] = {
"all", NULL };
5220 "Usage: bridge kick <bridge-id> <channel-name | all>\n"
5221 " Kick the <channel-name> channel out of the <bridge-id> bridge\n"
5222 " If all is specified as the channel name then all channels will be\n"
5223 " kicked out of the bridge.\n";
5227 return complete_bridge_live(a->word);
5231 return complete_bridge_participant(a->argv[2], a->word);
5237 return CLI_SHOWUSAGE;
5242 ast_cli(a->fd,
"Bridge '%s' not found\n", a->argv[2]);
5246 if (!strcasecmp(a->argv[3],
"all")) {
5249 ast_cli(a->fd,
"Kicking all channels from bridge '%s'\n", a->argv[2]);
5261 ast_cli(a->fd,
"Channel '%s' not found\n", a->argv[3]);
5266 ast_cli(a->fd,
"Kicking channel '%s' from bridge '%s'\n",
5267 ast_channel_name(chan), a->argv[2]);
5299 #define FORMAT_HDR "%-20s %-20s %8s %s\n"
5300 #define FORMAT_ROW "%-20s %-20s %8u %s\n"
5306 e->
command =
"bridge technology show";
5308 "Usage: bridge technology show\n"
5309 " List registered bridge technologies\n";
5315 ast_cli(a->fd, FORMAT_HDR,
"Name",
"Type",
"Priority",
"Suspended");
5332 static char *complete_bridge_technology(
const char *word)
5337 wordlen = strlen(word);
5340 if (!strncasecmp(cur->
name, word, wordlen)) {
5359 e->
command =
"bridge technology {suspend|unsuspend}";
5361 "Usage: bridge technology {suspend|unsuspend} <technology-name>\n"
5362 " Suspend or unsuspend a bridge technology.\n";
5366 return complete_bridge_technology(a->word);
5372 return CLI_SHOWUSAGE;
5375 suspend = !strcasecmp(a->argv[2],
"suspend");
5379 if (!strcasecmp(cur->
name, a->argv[3])) {
5393 ast_cli(a->fd,
"Suspended bridge technology '%s'\n", a->argv[3]);
5395 ast_cli(a->fd,
"Unsuspended bridge technology '%s'\n", a->argv[3]);
5398 ast_cli(a->fd,
"Bridge technology '%s' not found\n", a->argv[3]);
5405 AST_CLI_DEFINE(handle_bridge_show_all,
"List all bridges"),
5406 AST_CLI_DEFINE(handle_bridge_show_specific,
"Show information about a bridge"),
5408 AST_CLI_DEFINE(handle_bridge_destroy_specific,
"Destroy a bridge"),
5410 AST_CLI_DEFINE(handle_bridge_kick_channel,
"Kick a channel from a bridge"),
5411 AST_CLI_DEFINE(handle_bridge_technology_show,
"List registered bridge technologies"),
5412 AST_CLI_DEFINE(handle_bridge_technology_suspend,
"Suspend/unsuspend a bridge technology"),
5416 static int handle_manager_bridge_tech_suspend(
struct mansession *s,
const struct message *m,
int suspend)
5422 if (ast_strlen_zero(name)) {
5430 if (!strcasecmp(cur->
name, name)) {
5446 astman_send_ack(s, m, (suspend ?
"Suspended bridge technology" :
"Unsuspended bridge technology"));
5450 static int manager_bridge_tech_suspend(
struct mansession *s,
const struct message *m)
5452 return handle_manager_bridge_tech_suspend(s, m, 1);
5455 static int manager_bridge_tech_unsuspend(
struct mansession *s,
const struct message *m)
5457 return handle_manager_bridge_tech_suspend(s, m, 0);
5460 static int manager_bridge_tech_list(
struct mansession *s,
const struct message *m)
5472 if (!ast_strlen_zero(
id)) {
5485 "Event: BridgeTechnologyListItem\r\n"
5486 "BridgeTechnology: %s\r\n"
5487 "BridgeType: %s\r\n"
5488 "BridgePriority: %u\r\n"
5489 "BridgeSuspended: %s\r\n"
5513 static void bridge_prnt_obj(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
5520 prnt(where,
"%s %s chans:%u",
5529 static void bridge_cleanup(
void)
5537 ao2_cleanup(bridges);
5547 if (ast_stasis_bridging_init()) {
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Internal bridge impart wait condition and associated conditional.
struct ast_blind_transfer_message * ast_blind_transfer_message_create(int is_external, struct ast_channel *transferer, const char *exten, const char *context)
Create a blind transfer message to be published.
struct ast_bridge * ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
Create a new base class bridge.
int ast_bridge_interval_hook(struct ast_bridge_features *features, enum ast_bridge_hook_timer_option flags, unsigned int interval, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach an interval hook to a bridge features structure.
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
struct ao2_container * channels
Main Channel structure associated with a channel.
Local proxy channel special access.
enum bridge_channel_thread_state activity
The bridge channel thread activity.
Caching pattern for Stasis Message Bus API topics.
int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Build the connected line information data frame.
void ast_bridge_set_remb_estimated_bitrate(struct ast_bridge *bridge, float estimated_bitrate)
Force the REMB report estimated bitrate to a specific max value.
#define ast_frdup(fr)
Copies a frame.
struct ast_bridge_methods ast_bridge_base_v_table
Bridge base class virtual method table.
void( ao2_prnt_fn)(void *where, const char *fmt,...)
Print output.
int ast_bridge_talk_detector_hook(struct ast_bridge_features *features, ast_bridge_talking_indicate_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel talk detection hook to a bridge features structure.
void ast_bridge_run_after_goto(struct ast_channel *chan)
Run a PBX on any after bridge goto location.
struct timeval creationtime
struct ast_channel_snapshot_base * base
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
#define ast_bridge_lock_both(bridge1, bridge2)
Lock two bridges.
Asterisk main include file. File version handling, generic pbx functions.
struct ast_flags feature_flags
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
const ast_string_field uniqueid
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void ast_bridge_set_sfu_video_mode(struct ast_bridge *bridge)
Set the bridge to be a selective forwarding unit.
struct ast_bridge_features * features
int ast_bridging_init(void)
Initialize the bridging system.
int(* ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking)
Talking indicator callback.
ast_bridge_video_mode_type
Video source modes.
int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Enable a built in feature on a bridge features structure.
struct bridge_manager_request::@311 node
struct ast_bridge::@188 action_queue
#define AST_UNREAL_OPTIMIZE_BEGUN
struct ast_bridge * ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
Acquire the channel's bridge for transfer purposes.
struct ast_channel * ast_bridge_peer_nolock(struct ast_bridge *bridge, struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
int ast_attended_transfer_message_add_app(struct ast_attended_transfer_message *transfer_msg, const char *app, struct ast_channel *replace_channel)
Add details for an attended transfer to an application.
Message representing attended transfer.
struct ast_bridge * bridge_register(struct ast_bridge *bridge)
Register the new bridge with the system.
void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
unsigned int remb_send_interval
int(* ast_bridge_move_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt, struct ast_bridge *src, struct ast_bridge *dst)
Move indicator callback.
Structure that contains features information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define ast_channel_unref(c)
Decrease channel reference count.
int ast_bridge_features_limits_construct(struct ast_bridge_features_limits *limits)
Constructor function for ast_bridge_features_limits.
The arg parameter is a search key, but is not an object.
void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int cause)
Kick the channel out of the bridge.
Message published during a blind transfer.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
void(* suspend)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
Suspend a channel on a bridging technology instance for a bridge.
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
struct ast_unreal_pvt_callbacks * callbacks
ast_bridge_hook_remove_flags
struct ast_bridge_channel * ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
Get the peer bridge channel of a two party bridge.
unsigned int internal_mixing_interval
The mixing interval indicates how quickly softmix mixing should occur to mix audio.
char context[AST_MAX_CONTEXT]
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
descriptor for a cli entry.
struct ast_bridge_features * ast_bridge_features_new(void)
Allocate a new bridge features struct.
void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg)
Publish an attended transfer.
struct ao2_container * ast_bridges(void)
Returns the global bridges container.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static ast_bridge_hook_callback builtin_features_handlers[AST_BRIDGE_BUILTIN_END]
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Structure that contains a snapshot of information about a bridge.
void ast_local_lock_all(struct ast_channel *chan, void **tech_pvt, struct ast_channel **base_chan, struct ast_channel **base_owner)
Add a reference to the local channel's private tech, lock the local channel's private base...
int ast_callid_threadassoc_change(ast_callid callid)
Sets what is stored in the thread storage to the given callid if it does not match what is already th...
int(* start)(struct ast_bridge *bridge)
Request a bridge technology instance start operations.
unsigned int reconfigured
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
struct ast_bridge_video_mode video_mode
void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message)
Publish a blind transfer event.
const ast_string_field name
struct ast_channel * chan_old_vsrc
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
const ast_string_field video_source_id
struct ast_channel * owner
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Structure representing a snapshot of channel state.
struct ast_channel * chan_vsrc
enum bridge_channel_state state
struct ast_bridge_hook generic
This is used for both SINGLE_SRC_TALKER mode to set what channel should be the current single video f...
ast_bridge_builtin_interval
static int interval_wrapper_cb(struct ast_bridge_channel *bridge_channel, void *obj)
Wrapper for interval hooks that calls into the wrapped hook.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Structure for a data store type.
ast_channel_state
ast_channel states
struct ast_heap * ast_heap_destroy(struct ast_heap *h)
Destroy a max heap.
int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature)
Unregister a handler for a built in feature.
void(* stream_topology_changed)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
Callback for when a stream topology changes on the channel.
ast_bridge_hook_pvt_destructor destructor
struct ao2_container * dtmf_hooks
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
ast_bridge_dissolving_fn dissolving
int(* ast_bridge_hook_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
Hook callback type.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data)
Perform a blind transfer to a parking extension.
const char * ast_cause2str(int cause) attribute_pure
Gives the string form of a given cause code.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
remove a channel as a source of video for the bridge.
struct ast_channel * ast_channel_yank(struct ast_channel *yankee)
Gain control of a channel in the system.
int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_hook_callback callback, const char *dtmf)
Register a handler for a built in feature.
int ast_bridge_number_video_src(struct ast_bridge *bridge)
Returns the number of video sources currently active in the bridge.
unsigned int inhibit_merge
Count of the active temporary requests to inhibit bridge merges. Zero if merges are allowed...
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
Move a channel from one bridge to another.
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
static struct bridge_manager_controller * bridge_manager
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
void ast_brige_set_remb_behavior(struct ast_bridge *bridge, enum ast_bridge_video_sfu_remb_behavior behavior)
Set the REMB report generation behavior on a bridge.
static char builtin_features_dtmf[AST_BRIDGE_BUILTIN_END][MAXIMUM_DTMF_FEATURE_STRING]
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
void * ast_heap_pop(struct ast_heap *h)
Pop the max element off of the heap.
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
void(*const optimization_finished)(struct ast_unreal_pvt *p, int success, unsigned int id)
Called when an optimization attempt completed successfully.
int(* ast_bridge_builtin_set_limits_fn)(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits, enum ast_bridge_hook_remove_flags remove_flags)
Attach interval hooks to a bridge features structure.
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
struct ast_bridge_softmix softmix
int ast_attended_transfer_message_add_merge(struct ast_attended_transfer_message *transfer_msg, struct ast_bridge *final_bridge)
Add details for a bridge merge to an attended transfer message.
static ast_bridge_builtin_set_limits_fn builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_END]
int ast_bridge_queue_action(struct ast_bridge *bridge, struct ast_frame *action)
Put an action onto the specified bridge.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
const ast_string_field creator
void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
Run discarding any after bridge callbacks.
enum ast_bridge_video_sfu_remb_behavior remb_behavior
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_frame_subclass subclass
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
void ast_bridge_set_send_sdp_label(struct ast_bridge *bridge, unsigned int send_sdp_label)
Controls whether to send a "label" attribute in each stream in an SDP.
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)
Requests a channel.
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
int ast_bridge_dtmf_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a DTMF hook to a bridge features structure.
static struct ast_bridge_technology * find_best_technology(uint32_t capabilities, struct ast_bridge *bridge)
Helper function used to find the "best" bridge technology given specified capabilities.
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
void ast_bridge_features_merge(struct ast_bridge_features *into, const struct ast_bridge_features *from)
Merge one ast_bridge_features into another.
void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
Set the bridge to pick the strongest talker supporting video as the single source video feed...
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
int __ast_bridge_technology_register(struct ast_bridge_technology *technology, struct ast_module *module)
Register a bridge technology for use.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
struct ast_bridge_technology * technology
static int merge_container_cb(void *obj, void *data, int flags)
Callback for merging hook ao2_containers.
struct ast_flags feature_flags
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
unsigned int text_messaging
const char * ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type video_mode)
Converts an enum representation of a bridge video mode to string.
struct ast_attended_transfer_message * ast_attended_transfer_message_create(int is_external, struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge, struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge, struct ast_channel *transferee, struct ast_channel *transfer_target)
Create an Attended transfer message to be published.
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
enum ast_transfer_result result
void(* leave)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
Remove a channel from a bridging technology instance for a bridge.
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
void ast_bridge_merge_inhibit(struct ast_bridge *bridge, int request)
Adjust the bridge merge inhibit request count.
#define ast_heap_push(h, elm)
Push an element on to a heap.
int ast_bridge_hangup_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a hangup hook to a bridge features structure.
int(* compatible)(struct ast_bridge *bridge)
Check if a bridge is compatible with the bridging technology.
const ast_string_field technology
#define ast_bridge_channel_lock(bridge_channel)
Lock the bridge_channel.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
struct ast_bridge * ast_bridge_find_by_id(const char *bridge_id)
Find bridge by id.
struct ao2_container * ast_bridge_peers(struct ast_bridge *bridge)
Get a container of all channels in the bridge.
enum ast_bridge_hook_type type
ast_bridge_notify_masquerade_fn notify_masquerade
General Asterisk PBX channel definitions.
void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan)
Set a bridge to feed a single video source to all participants.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
void(*const optimization_started)(struct ast_unreal_pvt *p, struct ast_channel *source, enum ast_unreal_channel_indicator dest, unsigned int id)
Called when an optimization attempt has started.
void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
Publish a bridge merge.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value)
int(* write)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
Write a frame into the bridging technology instance for a bridge.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
int ast_bridge_join_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel join hook to a bridge features structure.
enum ast_bridge_preference preference
void ast_bridge_features_set_flag(struct ast_bridge_features *features, unsigned int flag)
Set a flag on a bridge channel features structure.
#define AST_MAX_EXTENSION
int ast_bridge_technology_unregister(struct ast_bridge_technology *technology)
Unregister a bridge technology from use.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define ast_channel_cleanup(c)
Cleanup a channel reference.
int ast_bridge_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, int merge_best_direction, struct ast_channel **kick_me, unsigned int num_kick)
Merge two bridges together.
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
int ast_bridge_move_hook(struct ast_bridge_features *features, ast_bridge_move_indicate_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel move detection hook to a bridge features structure.
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Private Bridging Channel API.
struct ast_bridge_hook_dtmf_parms dtmf
int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
Determine if a channel is a video src for the bridge.
int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
Unsuspend a channel from a bridge.
int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
Invoke a built in feature hook now.
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
A set of macros to manage forward-linked lists.
#define ast_malloc(len)
A wrapper for malloc()
#define MAXIMUM_DTMF_FEATURE_STRING
Maximum length of a DTMF feature string.
struct ast_bridge_snapshot * bridge
#define ast_debug(level,...)
Log a DEBUG message.
void ast_bridge_discard_after_goto(struct ast_channel *chan)
Discard channel after bridge goto location.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
void(* ast_bridge_hook_pvt_destructor)(void *hook_pvt)
Hook pvt destructor callback.
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Core PBX routines and definitions.
int ast_bridge_interval_unregister(enum ast_bridge_builtin_interval interval)
Unregisters a handler for a built in interval feature.
struct ast_heap * interval_hooks
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *chan1, struct ast_channel *chan2, struct ast_bridge *bridge1, struct ast_bridge *bridge2, struct ast_attended_transfer_message *transfer_msg)
Perform an attended transfer of a bridge.
#define ast_bridge_channel_unlock(bridge_channel)
Unlock the bridge_channel.
const struct ast_bridge_methods * v_table
unsigned int dtmf_passthrough
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
static void * bridge_channel_ind_thread(void *data)
Thread responsible for independent imparted bridged channels.
struct ast_bridge_snapshot * current_snapshot
Structure that contains information about a bridge.
void(* destroy)(struct ast_bridge *bridge)
Destroy a bridging technology instance for a bridge.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
struct ast_bridge * bridge
Support for dynamic strings.
const ast_string_field name
void ast_bridge_set_maximum_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
Adjust the maximum mixing sample rate of a bridge used during multimix mode.
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)
Impart a channel to a bridge (non-blocking)
Structure that contains configuration information for the limits feature.
#define ao2_unlink(container, obj)
Remove an object from a container.
int ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, struct ast_bridge_tech_optimizations *tech_args, enum ast_bridge_join_flags flags)
Join a channel to a bridge (blocking)
int ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Write a bridge action play file frame into the bridge.
enum ast_bridge_video_mode_type video_mode
struct ast_bridge_tech_optimizations tech_args
ast_bridge_hook_callback callback
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Connected Line/Party information.
The base pvt structure for local channel derivatives.
const ast_string_field name
void ast_bridge_features_limits_destroy(struct ast_bridge_features_limits *limits)
Destructor function for ast_bridge_features_limits.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
struct ast_channel * ast_bridge_peer(struct ast_bridge *bridge, struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_custom_callback_option flags, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
Queue a bridge action custom callback frame onto the bridge channel.
int ast_bridge_leave_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel leave hook to a bridge features structure.
int(* join)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
Add a channel to a bridging technology instance for a bridge.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
static struct ao2_container * bridges
void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
Adjust the internal mixing sample rate of a bridge used during multimix mode.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
void ast_bridge_set_transfer_variables(struct ast_channel *chan, const char *value, int attended)
Set the relevant transfer variables for a single channel.
int ast_parking_provider_registered(void)
Check whether a parking provider is registered.
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
ast_bridge_builtin_feature
Built in DTMF features.
Bridge virtual methods table definition.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
union ast_frame::@224 data
void ast_bridge_technology_suspend(struct ast_bridge_technology *technology)
Suspend a bridge technology from consideration.
#define ast_calloc(num, len)
A wrapper for calloc()
void ast_bridge_features_destroy(struct ast_bridge_features *features)
Destroy an allocated bridge features struct.
void ast_bridge_run_after_callback(struct ast_channel *chan)
Run any after bridge callback.
unsigned int inhibit_colp
int ast_bridge_features_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits, enum ast_bridge_hook_remove_flags remove_flags)
Limit the amount of time a channel may stay in the bridge and optionally play warning messages as tim...
struct ast_bridge_snapshot * ast_bridge_snapshot_create(struct ast_bridge *bridge)
Generate a snapshot of the bridge state. This is an ao2 object, so ao2_cleanup() to deallocate...
enum ast_bridge_optimization ast_bridges_allow_optimization(struct ast_bridge *chan_bridge, struct ast_bridge *peer_bridge)
Determine if bridges allow for optimization to occur betweem them.
void ast_bridge_set_remb_send_interval(struct ast_bridge *bridge, unsigned int remb_send_interval)
Set the interval at which a combined REMB frame will be sent to video sources.
struct ast_bridge_hook_timer_parms timer
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
ast_bridge_merge_priority_fn get_merge_priority
void ast_bridging_init_basic(void)
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
#define ast_bridge_channel_trylock(bridge_channel)
Try locking the bridge_channel.
unsigned int video_update_discard
static void wrap_hook(struct ast_bridge_features *features, struct ast_bridge_hook_timer *hook)
Wrap the provided interval hook and add it to features.
Support for logging to various files, console and syslog Configuration in file logger.conf.
Prototypes for public functions only of internal interest,.
const ast_string_field uniqueid
struct ast_channel * swap
Basic bridge subclass API.
int ast_bridge_kick(struct ast_bridge *bridge, struct ast_channel *chan)
Kick a channel from a bridge.
unsigned int num_channels
void ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
static void interval_wrapper_pvt_dtor(void *obj)
Destructor for the hook wrapper.
struct ao2_container * ast_bridge_peers_nolock(struct ast_bridge *bridge)
Get a container of all channels in the bridge.
struct ast_bridge_hook generic
#define ast_heap_create(init_height, cmp_fn, index_offset)
Create a max heap.
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel's bridge pointer.
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
struct stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular bridge.
#define ast_module_unref(mod)
Release a reference to the module.
int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
Suspend a channel temporarily from a bridge.
unsigned int send_sdp_label
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_bridge_set_binaural_active(struct ast_bridge *bridge, unsigned int binaural_active)
Activates the use of binaural signals in a conference bridge.
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
#define ast_bridge_lock(bridge)
Lock the bridge.
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
#define AST_YESNO(x)
return Yes or No depending on the argument.
struct ast_bridge_channels_list channels
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
struct ast_channel * chan
void * ast_heap_remove(struct ast_heap *h, void *elm)
Remove a specific element from a heap.
Replace objects with duplicate keys in container.
Structure that contains information regarding a channel in a bridge.
After Bridge Execution API.
#define ast_channel_ref(c)
Increase channel reference count.
ast_bridge_push_channel_fn push_peek
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
struct ao2_container * other_hooks
size_t ast_heap_size(struct ast_heap *h)
Get the current size of a heap.
void ast_local_unlock_all(void *tech_pvt, struct ast_channel *base_chan, struct ast_channel *base_owner)
Remove a reference to the given local channel's private tech, unlock the given local channel's privat...
void ast_bridge_technology_unsuspend(struct ast_bridge_technology *technology)
Unsuspend a bridge technology.
ast_bridge_video_sfu_remb_behavior
REMB report behaviors.
Structure that is the essence of a bridge technology.
int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Queue a bridge action play file frame onto the bridge channel.
void ast_bridge_features_remove(struct ast_bridge_features *features, enum ast_bridge_hook_remove_flags remove_flags)
Remove marked bridge channel feature hooks.
struct ast_channel * chan_vsrc
int ast_answer(struct ast_channel *chan)
Answer a channel.
void ast_bridge_notify_masquerade(struct ast_channel *chan)
Notify bridging that this channel was just masqueraded.
struct ast_vector_int media_types
AO2 object that wraps data for transfer_channel_cb.
int ast_bridge_interval_register(enum ast_bridge_builtin_interval interval, ast_bridge_builtin_set_limits_fn callback)
Register a handler for a built in interval feature.
void * ast_heap_peek(struct ast_heap *h, unsigned int index)
Peek at an element on a heap.
void ast_bridge_channel_stream_map(struct ast_bridge_channel *bridge_channel)
Maps a channel's stream topology to and from the bridge.
Data structure associated with a single frame of data.
Internal Asterisk hangup causes.
struct ast_flags remove_flags
Options provided by main asterisk program.
void ast_bridge_set_video_update_discard(struct ast_bridge *bridge, unsigned int video_update_discard)
Set the amount of time to discard subsequent video updates after a video update has been sent...
int ast_attended_transfer_message_add_link(struct ast_attended_transfer_message *transfer_msg, struct ast_channel *locals[2])
Add details for an attended transfer that has a link between bridges.
void(* transfer_channel_cb)(struct ast_channel *chan, struct transfer_channel_data *user_data, enum ast_transfer_type transfer_type)
Callback function type called during blind transfers.
ast_bridge_pull_channel_fn pull
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
int ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame onto the bridge channel with data.
static int play_file(struct ast_bridge_channel *bridge_channel, struct ast_channel *channel, const char *filename)
Playback the given filename and monitor for any dtmf interrupts.
ast_bridge_destructor_fn destroy
ast_bridge_push_channel_fn push
unsigned int interval_sequence
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
enum ast_frame_type frametype
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
void ast_format_duration_hh_mm_ss(int duration, char *buf, size_t length)
Formats a duration into HH:MM:SS.
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
int(* create)(struct ast_bridge *bridge)
Create a bridge technology instance for a bridge.
struct ast_channel_snapshot * transferee
int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
Remove a channel from a bridge.
const ast_string_field creator
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
int ast_bridge_unreal_optimize_out(struct ast_channel *chan, struct ast_channel *peer, struct ast_unreal_pvt *pvt)
Check and optimize out the unreal channels between bridges.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel)
Write an unhold frame into the bridge.
Say numbers and dates (maybe words one day too)
void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval)
Adjust the internal mixing interval of a bridge used during multimix mode.
void(* stop)(struct ast_bridge *bridge)
Request a bridge technology instance stop in preparation for being destroyed.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
const ast_string_field subclass
unsigned int internal_sample_rate
The internal sample rate softmix uses to mix channels.
ast_bridge_optimization
Tells, if optimization is allowed, how the optimization would be performed.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
enum ast_transfer_result ast_bridge_transfer_blind(int is_external, struct ast_channel *transferer, const char *exten, const char *context, transfer_channel_cb new_channel_cb, void *user_data)
Blind transfer target to the extension and context provided.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Structure specific to bridge technologies capable of performing talking optimizations.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
Setup the outgoing local channel to masquerade into a channel on ast_call().
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_channel_has_audio_frame_or_monitor(struct ast_channel *chan)
Check if the channel has active audiohooks, active framehooks, or a monitor.
enum ast_transfer_result result
char code[MAXIMUM_DTMF_FEATURE_STRING]
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
uint32_t allowed_capabilities
unsigned int maximum_sample_rate
The maximum sample rate softmix uses to mix channels.
Structure that is the essence of a feature hook.
unsigned int num_channels
int ast_bridge_setup_after_goto(struct ast_channel *chan)
Setup any after bridge goto location to begin execution.
int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_bridge_features *features, int play_tone, const char *xfersound)
Add an arbitrary channel to a bridge.
char exten[AST_MAX_EXTENSION]
Timing source management.
ast_bridge_hook_timer_option
static const char * tech_capability2str(uint32_t capabilities)
Structure for mutex and tracking information.
static int bridge_show_specific_print_channel(void *obj, void *arg, int flags)
Internal callback function for sending channels in a bridge to the CLI.
struct ast_bridge * bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
Initialize the base class of the bridge.
void ast_bridge_vars_set(struct ast_channel *chan, const char *name, const char *pvtid)
Sets BRIDGECHANNEL and BRIDGEPVTCALLID for a channel.
struct bridge_manager_controller::@312 service_requests
const ast_string_field name
static void * bridge_channel_depart_thread(void *data)
Thread responsible for imparted bridged channels to be departed.
struct ast_channel_snapshot * replace_channel
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define ast_bridge_trylock(bridge)
Try locking the bridge.
unsigned int construction_completed
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe)
Update information about talker energy for talker src video mode.
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
Setup the outgoing local channel to join a bridge on ast_call().
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
unsigned int binaural_active
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
void ast_bridge_publish_state(struct ast_bridge *bridge)
Publish the state of a bridge.
#define ao2_link(container, obj)
Add an object to a container.
Unreal channel derivative framework.