36 #include "asterisk/stasis_bridges.h"
37 #include "asterisk/stasis_channels.h"
44 #define SNAPSHOT_CHANNELS_BUCKETS 1
148 static struct ast_json *ast_channel_entered_bridge_to_json(
151 static struct ast_json *ast_channel_left_bridge_to_json(
154 static struct ast_json *ast_bridge_merge_message_to_json(
166 .to_json = ast_bridge_merge_message_to_json);
168 .to_json = ast_channel_entered_bridge_to_json);
170 .to_json = ast_channel_left_bridge_to_json);
172 .to_json = blind_transfer_to_json,
173 .to_ami = blind_transfer_to_ami);
175 .to_json = attended_transfer_to_json,
176 .to_ami = attended_transfer_to_ami);
181 return bridge_topic_all;
190 return bridge->
topic;
232 ast_channel_uniqueid(bridge_channel->
chan))) {
264 static void bridge_snapshot_update_dtor(
void *obj)
268 ast_debug(3,
"Update: %p Old: %s New: %s\n", update,
269 update->old_snapshot ? update->old_snapshot->
uniqueid :
"<none>",
270 update->new_snapshot ? update->new_snapshot->
uniqueid :
"<none>");
271 ao2_cleanup(update->old_snapshot);
272 ao2_cleanup(update->new_snapshot);
280 update = ao2_alloc_options(
sizeof(*update), bridge_snapshot_update_dtor,
285 update->old_snapshot =
ao2_bump(old);
286 update->new_snapshot =
ao2_bump(
new);
288 ast_debug(3,
"Update: %p Old: %s New: %s\n", update,
289 update->old_snapshot ? update->old_snapshot->
uniqueid :
"<none>",
290 update->new_snapshot ? update->new_snapshot->
uniqueid :
"<none>");
295 int bridge_topics_init(
struct ast_bridge *bridge)
300 if (ast_strlen_zero(bridge->
uniqueid)) {
301 ast_log(LOG_ERROR,
"Bridge id initialization required\n");
311 ast_free(topic_name);
312 if (!bridge->
topic) {
319 void bridge_topics_destroy(
struct ast_bridge *bridge)
324 ast_assert(bridge != NULL);
356 ast_assert(bridge != NULL);
363 update = bridge_snapshot_update_create(bridge->
current_snapshot, new_snapshot);
381 static void bridge_publish_state_from_blob(
struct ast_bridge *bridge,
387 ast_assert(obj != NULL);
411 ao2_cleanup(msg->
to);
413 ao2_cleanup(msg->
from);
429 if (!msg->
to || !msg->
from) {
438 static struct ast_json *ast_bridge_merge_message_to_json(
446 if (!json_bridge_to || !json_bridge_from) {
454 "type",
"BridgeMerged",
456 "bridge", json_bridge_to,
457 "bridge_from", json_bridge_from);
465 if (!ast_bridge_merge_message_type()) {
469 ast_assert(to != NULL);
470 ast_assert(from != NULL);
489 static void bridge_blob_dtor(
void *obj)
492 ao2_cleanup(
event->bridge);
493 event->bridge = NULL;
494 ao2_cleanup(
event->channel);
495 event->channel = NULL;
513 obj = ao2_alloc(
sizeof(*obj), bridge_blob_dtor);
520 if (obj->
bridge == NULL) {
559 obj = ao2_alloc(
sizeof(*obj), bridge_blob_dtor);
564 if (bridge_snapshot) {
593 blob =
ast_json_pack(
"{s: s}",
"swap", ast_channel_uniqueid(swap));
629 static struct ast_json *simple_bridge_channel_event(
633 const struct timeval *tv,
639 if (!json_bridge || !json_channel) {
649 "bridge", json_bridge,
650 "channel", json_channel);
653 struct ast_json *ast_channel_entered_bridge_to_json(
659 return simple_bridge_channel_event(
"ChannelEnteredBridge", obj->
bridge,
663 struct ast_json *ast_channel_left_bridge_to_json(
669 return simple_bridge_channel_event(
"ChannelLeftBridge", obj->
bridge,
685 (item = ao2_iterator_next(&it)); ao2_cleanup(item)) {
703 static const char *capability2str(uint32_t capabilities)
719 if (snapshot == NULL) {
723 json_channels = container_to_json_array(snapshot->
channels, sanitize);
724 if (!json_channels) {
728 json_bridge =
ast_json_pack(
"{s: s, s: s, s: s, s: s, s: s, s: s, s: o, s: o, s: s}",
734 "name", snapshot->
name,
735 "channels", json_channels,
767 if (!snapshot_pair->bridge_snapshot) {
773 if (!snapshot_pair->channel_snapshot) {
788 ao2_cleanup(pair->bridge_snapshot);
789 ao2_cleanup(pair->channel_snapshot);
792 static const char *result_strs[] = {
804 struct ast_json *json_transferee = NULL;
806 struct ast_json *json_replace = NULL;
810 if (!json_transferer) {
816 if (!json_transferee) {
831 out =
ast_json_pack(
"{s: s, s: o, s: o, s: s, s: s, s: s, s: o}",
832 "type",
"BridgeBlindTransfer",
834 "channel", json_transferer,
835 "exten", transfer_msg->
exten,
836 "context", transfer_msg->
context,
837 "result", result_strs[transfer_msg->
result],
857 if (transfer_msg->
bridge) {
859 transfer_msg->
bridge, sanitize);
883 if (!transferer_state) {
887 if (transfer_msg->
bridge) {
897 if (!transferee_state) {
910 result_strs[transfer_msg->
result],
916 transfer_msg->
exten);
919 static void blind_transfer_dtor(
void *obj)
934 msg = ao2_alloc(
sizeof(*msg), blind_transfer_dtor);
972 struct ast_json *json_transferer1, *json_transferer2, *json_bridge, *json_channel;
973 struct ast_json *json_transferee = NULL, *json_target = NULL;
978 if (!json_transferer1) {
983 if (!json_transferer2) {
990 if (!json_transferee) {
997 if (transfer_msg->
target) {
1008 "type",
"BridgeAttendedTransfer",
1010 "transferer_first_leg", json_transferer1,
1011 "transferer_second_leg", json_transferer2,
1012 "result", result_strs[transfer_msg->
result],
1048 case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
1052 case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
1055 case AST_ATTENDED_TRANSFER_DEST_APP:
1059 case AST_ATTENDED_TRANSFER_DEST_LINK:
1063 if (!json_channel) {
1069 if (!json_channel) {
1075 case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
1079 if (!json_channel) {
1091 case AST_ATTENDED_TRANSFER_DEST_FAIL:
1116 if (!variable_data) {
1122 if (!transferer1_state || !transferer2_state) {
1127 if (!transferee_state) {
1132 if (transfer_msg->
target) {
1134 if (!target_state) {
1142 if (!bridge1_state) {
1150 if (!bridge2_state) {
1156 case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
1160 case AST_ATTENDED_TRANSFER_DEST_APP:
1161 case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
1165 case AST_ATTENDED_TRANSFER_DEST_LINK:
1168 if (!local1_state || !local2_state) {
1175 case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
1180 case AST_ATTENDED_TRANSFER_DEST_FAIL:
1193 "IsExternal: %s\r\n"
1195 result_strs[transfer_msg->
result],
1206 static void attended_transfer_dtor(
void *obj)
1215 ao2_cleanup(msg->
target);
1217 if (msg->
dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
1221 for (i = 0; i < ARRAY_LEN(msg->dest.
links); ++i) {
1222 ao2_cleanup(msg->dest.
links[i]);
1233 transfer_msg = ao2_alloc(
sizeof(*transfer_msg), attended_transfer_dtor);
1234 if (!transfer_msg) {
1238 if (bridge_channel_snapshot_pair_init(to_transferee, transferee_bridge, &transfer_msg->
to_transferee) ||
1239 bridge_channel_snapshot_pair_init(to_transfer_target, target_bridge, &transfer_msg->
to_transfer_target)) {
1240 ao2_cleanup(transfer_msg);
1247 ao2_cleanup(transfer_msg);
1250 }
else if (transferee_bridge) {
1254 ao2_cleanup(transferee);
1256 ao2_cleanup(transfer_msg);
1262 if (transfer_target) {
1264 if (!transfer_msg->
target) {
1265 ao2_cleanup(transfer_msg);
1268 }
else if (target_bridge) {
1270 if (transfer_target) {
1272 ao2_cleanup(transfer_target);
1273 if (!transfer_msg->
target) {
1274 ao2_cleanup(transfer_msg);
1280 return transfer_msg;
1286 transfer_msg->
dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
1288 sizeof(transfer_msg->dest.
bridge));
1296 transfer_msg->
dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
1316 transfer_msg->
dest_type = replace_channel ? AST_ATTENDED_TRANSFER_DEST_LOCAL_APP : AST_ATTENDED_TRANSFER_DEST_APP;
1318 if (replace_channel) {
1335 transfer_msg->
dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
1336 for (i = 0; i < 2; ++i) {
1338 if (!transfer_msg->dest.
links[i]) {
1364 ast_assert(!ast_strlen_zero(uniqueid));
1392 static void stasis_bridging_cleanup(
void)
1401 ao2_cleanup(bridge_topic_pool);
1402 bridge_topic_pool = NULL;
1403 ao2_cleanup(bridge_topic_all);
1404 bridge_topic_all = NULL;
1407 int ast_stasis_bridging_init(
void)
1414 if (!bridge_topic_all) {
1418 if (!bridge_topic_pool) {
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 containing info for an AMI event to send out.
struct ao2_container * channels
Main Channel structure associated with a channel.
Caching pattern for Stasis Message Bus API topics.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
struct timeval creationtime
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
struct ast_flags feature_flags
const ast_string_field uniqueid
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
static struct ast_bridge_merge_message * bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
Bridge merge message creation helper.
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_channel_snapshot * channel
struct ast_bridge * ast_bridge_find_by_id(const char *bridge_id)
Find bridge by id.
char exten[AST_MAX_EXTENSION]
Message published during a blind transfer.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
Publish a bridge channel leave event.
void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
Publish a bridge channel enter event.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
int(* channel_id)(const char *channel_id)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg)
Publish an attended transfer.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Structure that contains a snapshot of information about a bridge.
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
const ast_string_field video_source_id
Structure representing a snapshot of channel state.
struct stasis_message * ast_bridge_blob_create_from_snapshots(struct stasis_message_type *message_type, struct ast_bridge_snapshot *bridge_snapshot, struct ast_channel_snapshot *chan_snapshot, struct ast_json *blob)
Creates a ast_bridge_blob message from snapshots.
struct ast_channel * chan_vsrc
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
struct ast_channel_snapshot * target
const ast_string_field uniqueid
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct stasis_topic * stasis_topic_pool_get_topic(struct stasis_topic_pool *pool, const char *topic_name)
Find or create a topic in the pool.
char bridge[AST_UUID_STR_LEN]
void ast_free_ptr(void *ptr)
free() wrapper
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.
struct ast_bridge_channel_snapshot_pair to_transferee
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.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
const ast_string_field creator
Structure containing callbacks for Stasis message sanitization.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
struct ast_str * ast_manager_build_bridge_state_string_prefix(const struct ast_bridge_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a bridge snapshot.
struct stasis_topic_pool * stasis_topic_pool_create(struct stasis_topic *pooled_topic)
Create a topic pool that routes messages from dynamically generated topics to the given topic...
static void bridge_snapshot_dtor(void *obj)
Destructor for bridge snapshots.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
struct ast_bridge_technology * technology
struct ast_bridge_channel_snapshot_pair to_transfer_target
struct ast_bridge_snapshot * bridge
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.
enum ast_transfer_result result
const ast_string_field technology
General Asterisk PBX channel definitions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
Publish a bridge merge.
struct ast_channel_snapshot * links[2]
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
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_channel_snapshot * transferee
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
struct ast_channel_snapshot * replace_channel
struct ast_bridge_snapshot * bridge
#define ast_debug(level,...)
Log a DEBUG message.
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
struct ast_str * ast_manager_build_bridge_state_string(const struct ast_bridge_snapshot *snapshot)
Generate the AMI message body from a bridge snapshot.
Blob of data associated with a bridge.
static void bridge_merge_message_dtor(void *obj)
Destructor for bridge merge messages.
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
enum ast_attended_transfer_dest_type dest_type
const struct ast_bridge_methods * v_table
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
void stasis_topic_pool_delete_topic(struct stasis_topic_pool *pool, const char *topic_name)
Delete a topic from the topic pool.
struct ast_bridge_snapshot * current_snapshot
Structure that contains information about a bridge.
struct ast_channel_snapshot * transferer
Support for dynamic strings.
const ast_string_field name
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
enum ast_bridge_video_mode_type video_mode
const char * stasis_topic_name(const struct stasis_topic *topic)
Return the name of a topic.
char context[AST_MAX_CONTEXT]
struct ast_bridge_channel_snapshot_pair threeway
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
struct timeval creationtime
#define ast_bridge_unlock(bridge)
Unlock the bridge.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
static const char * stasis
Dialplan application name.
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...
int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_message *transfer_msg, struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge)
Add details for an attended transfer that was resolved as a three-way call.
const ast_string_field uniqueid
struct ast_flags feature_flags
unsigned int num_channels
struct ast_bridge_snapshot * from
struct stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular bridge.
#define ast_bridge_lock(bridge)
Lock the bridge.
struct ast_bridge_channels_list channels
Message representing the merge of two bridges.
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
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...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
struct ast_channel * chan_vsrc
struct stasis_topic * topic
Abstract JSON element (object, array, string, int, ...).
struct ast_json * ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_bridge_snapshot.
struct ast_json * ast_json_boolean(int value)
Get the JSON boolean corresponding to value.
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.
struct ast_channel_snapshot * transferee
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
const ast_string_field creator
struct stasis_message * ast_bridge_blob_create(struct stasis_message_type *message_type, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_json *blob)
Creates a ast_bridge_blob message.
const ast_string_field subclass
STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type)
Define bridge message types.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
enum ast_transfer_result result
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
unsigned int num_channels
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
const ast_string_field name
struct ast_channel_snapshot * replace_channel
struct ast_bridge_snapshot * to
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
void ast_bridge_publish_state(struct ast_bridge *bridge)
Publish the state of a bridge.
Pair showing a bridge snapshot and a specific channel snapshot belonging to the bridge.