<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/9294">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Richard Mudgett: Looks good to me, but someone else must approve
Kevin Harwell: Looks good to me, approved
Jenkins2: Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_confbridge: Move participant info code to confbridge_manager.<br><br>With the participant info code in app_confbridge, we were still<br>in the process of adding the channel to the bridge when trying to send<br>an in-dialog MESSAGE. This caused 2 threads to grab the channel<br>blocking flag at the same time. To mitigate this, the participant<br>info code was moved to confbridge_manager so it runs after all<br>channel/bridge actions have finished.<br><br>Change-Id: I228806ac153074f45e0b35d5236166e92e132abd<br>---<br>M apps/app_confbridge.c<br>M apps/confbridge/confbridge_manager.c<br>M apps/confbridge/include/confbridge.h<br>3 files changed, 352 insertions(+), 312 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c<br>index 7680603..2bc6014 100644<br>--- a/apps/app_confbridge.c<br>+++ b/apps/app_confbridge.c<br>@@ -550,314 +550,6 @@<br> }<br> <br> <br>-static struct ast_json *channel_to_json(struct ast_channel_snapshot *channel_snapshot,<br>- struct ast_json *conf_blob, struct ast_json *labels_blob)<br>-{<br>- struct ast_json *json_channel = ast_channel_snapshot_to_json(channel_snapshot, NULL);<br>-<br>- if (!json_channel) {<br>- return NULL;<br>- }<br>-<br>- /* These items are removed for privacy reasons. */<br>- ast_json_object_del(json_channel, "dialplan");<br>- ast_json_object_del(json_channel, "connected");<br>- ast_json_object_del(json_channel, "accountcode");<br>-<br>- /* conf_blob contains flags such as talking, admin, mute, etc. */<br>- if (conf_blob) {<br>- struct ast_json *conf_copy = ast_json_copy(conf_blob);<br>-<br>- if (!conf_copy) {<br>- ast_json_unref(json_channel);<br>- return NULL;<br>- }<br>- ast_json_object_del(conf_copy, "conference");<br>- ast_json_object_update(json_channel, conf_copy);<br>- ast_json_unref(conf_copy);<br>- }<br>-<br>- /* labels_blob contains the msid labels to correlate to streams. */<br>- if (labels_blob) {<br>- ast_json_object_update(json_channel, labels_blob);<br>- }<br>-<br>- return json_channel;<br>-}<br>-<br>-static struct ast_json *bridge_to_json(struct ast_bridge_snapshot *bridge_snapshot)<br>-{<br>- struct ast_json *json_bridge = ast_bridge_snapshot_to_json(bridge_snapshot, NULL);<br>-<br>- if (!json_bridge) {<br>- return NULL;<br>- }<br>-<br>- /* These items have no use in the context of bridge participant info. */<br>- ast_json_object_del(json_bridge, "technology");<br>- ast_json_object_del(json_bridge, "bridge_type");<br>- ast_json_object_del(json_bridge, "bridge_class");<br>- ast_json_object_del(json_bridge, "creator");<br>- ast_json_object_del(json_bridge, "channels");<br>-<br>- return json_bridge;<br>-}<br>-<br>-static struct ast_json *pack_bridge_and_channels(<br>- struct ast_json *json_bridge, struct ast_json *json_channels,<br>- struct stasis_message * msg)<br>-{<br>- const struct timeval *tv = stasis_message_timestamp(msg);<br>- const char *msg_name = confbridge_event_type_to_string(stasis_message_type(msg));<br>- const char *fmt = ast_json_typeof(json_channels) == AST_JSON_ARRAY ?<br>- "{s: s, s: o, s: o, s: o }" : "{s: s, s: o, s: o, s: [ o ] }";<br>-<br>- return ast_json_pack(fmt,<br>- "type", msg_name,<br>- "timestamp", ast_json_timeval(*tv, NULL),<br>- "bridge", json_bridge,<br>- "channels", json_channels);<br>-}<br>-<br>-static struct ast_json *pack_snapshots( struct ast_bridge_snapshot *bridge_snapshot,<br>- struct ast_channel_snapshot *channel_snapshot, struct ast_json *conf_blob,<br>- struct ast_json *labels_blob, struct stasis_message * msg)<br>-{<br>- struct ast_json *json_bridge;<br>- struct ast_json *json_channel;<br>-<br>- json_bridge = bridge_to_json(bridge_snapshot);<br>- json_channel = channel_to_json(channel_snapshot, conf_blob, labels_blob);<br>-<br>- return pack_bridge_and_channels(json_bridge, json_channel, msg);<br>-}<br>-<br>-enum label_direction {<br>- LABEL_DIRECTION_SRC,<br>- LABEL_DIRECTION_DEST,<br>-};<br>-<br>-static struct ast_stream *get_stream(struct ast_stream_topology *topology,<br>- enum ast_media_type m_type)<br>-{<br>- int count;<br>- int i;<br>-<br>- count = ast_stream_topology_get_count(topology);<br>- if (count < 0) {<br>- return NULL;<br>- }<br>-<br>- for (i = 0; i < count; i++) {<br>- struct ast_stream *s;<br>- enum ast_stream_state s_state;<br>- enum ast_media_type s_type;<br>-<br>- s = ast_stream_topology_get_stream(topology, i);<br>- s_state = ast_stream_get_state(s);<br>- s_type = ast_stream_get_type(s);<br>- if (s_type == m_type<br>- && (s_state == AST_STREAM_STATE_SENDRECV || s_state == AST_STREAM_STATE_RECVONLY)) {<br>- return s;<br>- }<br>- }<br>-<br>- return NULL;<br>-}<br>-<br>-static struct ast_json *get_media_labels(struct confbridge_conference *conference,<br>- struct ast_channel *src_chan, struct ast_channel *dest_chan, enum label_direction dir)<br>-{<br>- struct ast_stream_topology *topology;<br>- struct ast_stream *stream;<br>- const char *curr_a_label;<br>- const char *a_label = NULL;<br>- const char *v_label = NULL;<br>- struct ast_json *labels = ast_json_array_create();<br>-<br>- if (!labels) {<br>- return NULL;<br>- }<br>-<br>- topology = ast_channel_get_stream_topology(dir == LABEL_DIRECTION_SRC ? src_chan : dest_chan);<br>- stream = get_stream(topology, AST_MEDIA_TYPE_AUDIO);<br>- curr_a_label = stream ? ast_stream_get_metadata(stream, "MSID:LABEL") : NULL;<br>- a_label = curr_a_label ?: conference->bridge->uniqueid;<br>- ast_json_array_append(labels, ast_json_string_create(a_label));<br>-<br>- topology = ast_channel_get_stream_topology(dir == LABEL_DIRECTION_SRC ? dest_chan : src_chan);<br>- stream = get_stream(topology, AST_MEDIA_TYPE_VIDEO);<br>- v_label = stream ? ast_stream_get_metadata(stream, "MSID:LABEL") : NULL;<br>- if (v_label) {<br>- ast_json_array_append(labels, ast_json_string_create(v_label));<br>- }<br>-<br>- return ast_json_pack("{s: o }", "media_source_track_labels", labels);<br>-}<br>-<br>-static void send_message(const char *msg_name, char *conf_name, struct ast_json *json_object,<br>- struct ast_channel *chan)<br>-{<br>- struct ast_msg_data *data_msg;<br>- struct ast_msg_data_attribute attrs[] = {<br>- { .type = AST_MSG_DATA_ATTR_FROM, conf_name },<br>- { .type = AST_MSG_DATA_ATTR_CONTENT_TYPE, .value = "application/x-asterisk-confbridge-event+json"},<br>- { .type = AST_MSG_DATA_ATTR_BODY, },<br>- };<br>- char *json;<br>- int rc = 0;<br>-<br>- json = ast_json_dump_string_format(json_object, AST_JSON_PRETTY);<br>- if (!json) {<br>- ast_log(LOG_ERROR, "Unable to convert json_object for %s message to string\n", msg_name);<br>- return;<br>- }<br>- attrs[2].value = json;<br>-<br>- data_msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_IN_DIALOG, attrs, ARRAY_LEN(attrs));<br>- if (!data_msg) {<br>- ast_log(LOG_ERROR, "Unable to create %s message for channel '%s'\n", msg_name,<br>- ast_channel_name(chan));<br>- ast_json_free(json);<br>- return;<br>- }<br>-<br>- rc = ast_sendtext_data(chan, data_msg);<br>- ast_free(data_msg);<br>- if (rc != 0) {<br>- /* Don't complain if we can't send a leave message. The channel is probably gone. */<br>- if (strcmp(confbridge_event_type_to_string(confbridge_leave_type()), msg_name) != 0) {<br>- ast_log(LOG_ERROR, "Failed to queue %s message to '%s'\n%s\n", msg_name,<br>- ast_channel_name(chan), json);<br>- }<br>- ast_json_free(json);<br>- return;<br>- }<br>-<br>- ast_debug(3, "Queued %s message to '%s'\n%s\n", msg_name, ast_channel_name(chan), json);<br>- ast_json_free(json);<br>-}<br>-<br>-static void send_event_to_participants(struct confbridge_conference *conference,<br>- struct ast_channel *chan, struct stasis_message * msg)<br>-{<br>- struct ast_bridge_blob *obj = stasis_message_data(msg);<br>- struct ast_json *extras = obj->blob;<br>- struct user_profile u_profile = {{0}};<br>- int source_send_events = 0;<br>- int source_echo_events = 0;<br>- struct ast_json* json_channels = NULL;<br>- struct confbridge_user *user;<br>- const char *msg_name = confbridge_event_type_to_string(stasis_message_type(msg));<br>-<br>- ast_debug(3, "Distributing %s event to participants\n", msg_name);<br>-<br>- /* This could be a channel level event or a bridge level event */<br>- if (chan) {<br>- if (!conf_find_user_profile(chan, NULL, &u_profile)) {<br>- ast_log(LOG_ERROR, "Unable to retrieve user profile for channel '%s'\n",<br>- ast_channel_name(chan));<br>- return;<br>- }<br>- source_send_events = ast_test_flag(&u_profile, USER_OPT_SEND_EVENTS);<br>- source_echo_events = ast_test_flag(&u_profile, USER_OPT_ECHO_EVENTS);<br>- ast_debug(3, "send_events: %d echo_events: %d for profile %s\n",<br>- source_send_events, source_echo_events, u_profile.name);<br>- }<br>-<br>- /* Now send a message to the participants with the json string. */<br>- ao2_lock(conference);<br>- AST_LIST_TRAVERSE(&conference->active_list, user, list) {<br>- struct ast_json *json_object;<br>- struct ast_json* source_json_labels = NULL;<br>-<br>- /*<br>- * If the msg type is join, we need to capture all targets channel info so we can<br>- * send a welcome message to the source channel with all current participants.<br>- */<br>- if (source_send_events && stasis_message_type(msg) == confbridge_join_type()) {<br>- struct ast_channel_snapshot *target_snapshot;<br>- struct ast_json *target_json_channel;<br>- struct ast_json *target_json_labels;<br>-<br>- target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(user->chan));<br>- if (!target_snapshot) {<br>- ast_log(LOG_ERROR, "Unable to get a channel snapshot for '%s'\n",<br>- ast_channel_name(user->chan));<br>- continue;<br>- }<br>-<br>- target_json_labels = get_media_labels(conference, chan, user->chan, LABEL_DIRECTION_SRC);<br>- target_json_channel = channel_to_json(target_snapshot, extras, target_json_labels);<br>- ao2_ref(target_snapshot, -1);<br>- ast_json_unref(target_json_labels);<br>-<br>- if (!json_channels) {<br>- json_channels = ast_json_array_create();<br>- if (!json_channels) {<br>- ast_log(LOG_ERROR, "Unable to allocate json array\n");<br>- ast_json_unref(target_json_channel);<br>- ast_json_unref(target_json_labels);<br>- return;<br>- }<br>- }<br>-<br>- ast_json_array_append(json_channels, target_json_channel);<br>- }<br>-<br>- /* Don't send a message to the user that triggered the event. */<br>- if (!source_echo_events && user->chan == chan) {<br>- ast_debug(3, "Skipping queueing %s message to '%s'. Same channel.\n", msg_name,<br>- ast_channel_name(user->chan));<br>- continue;<br>- }<br>-<br>- /* Don't send a message to users in profiles not sending events. */<br>- if (!ast_test_flag(&user->u_profile, USER_OPT_SEND_EVENTS)) {<br>- ast_debug(3, "Skipping queueing %s message to '%s'. Not receiving events.\n", msg_name,<br>- ast_channel_name(user->chan));<br>- continue;<br>- }<br>-<br>- source_json_labels = get_media_labels(conference, chan, user->chan, LABEL_DIRECTION_DEST);<br>- ast_json_object_update(extras, source_json_labels);<br>-<br>- json_object = pack_snapshots(obj->bridge, obj->channel, extras, source_json_labels, msg);<br>- ast_json_unref(source_json_labels);<br>-<br>- if (!json_object) {<br>- ast_log(LOG_ERROR, "Unable to convert %s message to json\n", msg_name);<br>- continue;<br>- }<br>-<br>- send_message(msg_name, conference->name, json_object, user->chan);<br>- ast_json_unref(json_object);<br>- }<br>- ao2_unlock(conference);<br>-<br>- /*<br>- * If this is a join event, send the welcome message to just the joining user<br>- * if it's not audio-only or otherwise restricted.<br>- */<br>- if (source_send_events && json_channels<br>- && stasis_message_type(msg) == confbridge_join_type()) {<br>- struct ast_json *json_object;<br>- struct ast_json *json_bridge;<br>- const char *welcome_msg_name = confbridge_event_type_to_string(confbridge_welcome_type());<br>-<br>- json_bridge = bridge_to_json(obj->bridge);<br>- json_object = pack_bridge_and_channels(json_bridge, json_channels, msg);<br>- if (!json_object) {<br>- ast_log(LOG_ERROR, "Unable to convert ConfbridgeWelcome message to json\n");<br>- return;<br>- }<br>- ast_json_string_set(ast_json_object_get(json_object, "type"), welcome_msg_name);<br>-<br>- send_message(welcome_msg_name, conference->name, json_object, chan);<br>- ast_json_unref(json_object);<br>- }<br>-}<br>-<br> static void send_conf_stasis(struct confbridge_conference *conference, struct ast_channel *chan,<br> struct stasis_message_type *type, struct ast_json *extras, int channel_topic)<br> {<br>@@ -882,10 +574,6 @@<br> ast_bridge_unlock(conference->bridge);<br> if (!msg) {<br> return;<br>- }<br>-<br>- if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {<br>- send_event_to_participants(conference, chan, msg);<br> }<br> <br> if (channel_topic) {<br>@@ -1023,6 +711,11 @@<br> return 0;<br> }<br> <br>+struct confbridge_conference *conf_find_bridge(const char *conference_name)<br>+{<br>+ return ao2_find(conference_bridges, conference_name, OBJ_KEY);<br>+}<br>+<br> /*!<br> * \internal<br> * \brief Returns whether or not conference is being recorded.<br>diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c<br>index 823e69a..a101530 100644<br>--- a/apps/confbridge/confbridge_manager.c<br>+++ b/apps/confbridge/confbridge_manager.c<br>@@ -33,6 +33,8 @@<br> #include "asterisk/manager.h"<br> #include "asterisk/stasis_message_router.h"<br> #include "include/confbridge.h"<br>+#include "asterisk/message.h"<br>+#include "asterisk/stream.h"<br> <br> /*** DOCUMENTATION<br> <managerEvent language="en_US" name="ConfbridgeStart"><br>@@ -271,6 +273,327 @@<br> }<br> }<br> <br>+static struct ast_json *channel_to_json(struct ast_channel_snapshot *channel_snapshot,<br>+ struct ast_json *conf_blob, struct ast_json *labels_blob)<br>+{<br>+ struct ast_json *json_channel = ast_channel_snapshot_to_json(channel_snapshot, NULL);<br>+<br>+ if (!json_channel) {<br>+ return NULL;<br>+ }<br>+<br>+ /* These items are removed for privacy reasons. */<br>+ ast_json_object_del(json_channel, "dialplan");<br>+ ast_json_object_del(json_channel, "connected");<br>+ ast_json_object_del(json_channel, "accountcode");<br>+<br>+ /* conf_blob contains flags such as talking, admin, mute, etc. */<br>+ if (conf_blob) {<br>+ struct ast_json *conf_copy = ast_json_copy(conf_blob);<br>+<br>+ if (!conf_copy) {<br>+ ast_json_unref(json_channel);<br>+ return NULL;<br>+ }<br>+ ast_json_object_del(conf_copy, "conference");<br>+ ast_json_object_update(json_channel, conf_copy);<br>+ ast_json_unref(conf_copy);<br>+ }<br>+<br>+ /* labels_blob contains the msid labels to correlate to streams. */<br>+ if (labels_blob) {<br>+ ast_json_object_update(json_channel, labels_blob);<br>+ }<br>+<br>+ return json_channel;<br>+}<br>+<br>+static struct ast_json *bridge_to_json(struct ast_bridge_snapshot *bridge_snapshot)<br>+{<br>+ struct ast_json *json_bridge = ast_bridge_snapshot_to_json(bridge_snapshot, NULL);<br>+<br>+ if (!json_bridge) {<br>+ return NULL;<br>+ }<br>+<br>+ /* These items have no use in the context of bridge participant info. */<br>+ ast_json_object_del(json_bridge, "technology");<br>+ ast_json_object_del(json_bridge, "bridge_type");<br>+ ast_json_object_del(json_bridge, "bridge_class");<br>+ ast_json_object_del(json_bridge, "creator");<br>+ ast_json_object_del(json_bridge, "channels");<br>+<br>+ return json_bridge;<br>+}<br>+<br>+static struct ast_json *pack_bridge_and_channels(<br>+ struct ast_json *json_bridge, struct ast_json *json_channels,<br>+ struct stasis_message * msg)<br>+{<br>+ const struct timeval *tv = stasis_message_timestamp(msg);<br>+ const char *msg_name = confbridge_event_type_to_string(stasis_message_type(msg));<br>+ const char *fmt = ast_json_typeof(json_channels) == AST_JSON_ARRAY ?<br>+ "{s: s, s: o, s: o, s: o }" : "{s: s, s: o, s: o, s: [ o ] }";<br>+<br>+ return ast_json_pack(fmt,<br>+ "type", msg_name,<br>+ "timestamp", ast_json_timeval(*tv, NULL),<br>+ "bridge", json_bridge,<br>+ "channels", json_channels);<br>+}<br>+<br>+static struct ast_json *pack_snapshots( struct ast_bridge_snapshot *bridge_snapshot,<br>+ struct ast_channel_snapshot *channel_snapshot, struct ast_json *conf_blob,<br>+ struct ast_json *labels_blob, struct stasis_message * msg)<br>+{<br>+ struct ast_json *json_bridge;<br>+ struct ast_json *json_channel;<br>+<br>+ json_bridge = bridge_to_json(bridge_snapshot);<br>+ json_channel = channel_to_json(channel_snapshot, conf_blob, labels_blob);<br>+<br>+ return pack_bridge_and_channels(json_bridge, json_channel, msg);<br>+}<br>+<br>+enum label_direction {<br>+ LABEL_DIRECTION_SRC,<br>+ LABEL_DIRECTION_DEST,<br>+};<br>+<br>+static struct ast_stream *get_stream(struct ast_stream_topology *topology,<br>+ enum ast_media_type m_type)<br>+{<br>+ int count;<br>+ int i;<br>+<br>+ count = ast_stream_topology_get_count(topology);<br>+ if (count < 0) {<br>+ return NULL;<br>+ }<br>+<br>+ for (i = 0; i < count; i++) {<br>+ struct ast_stream *s;<br>+ enum ast_stream_state s_state;<br>+ enum ast_media_type s_type;<br>+<br>+ s = ast_stream_topology_get_stream(topology, i);<br>+ s_state = ast_stream_get_state(s);<br>+ s_type = ast_stream_get_type(s);<br>+ if (s_type == m_type<br>+ && (s_state == AST_STREAM_STATE_SENDRECV || s_state == AST_STREAM_STATE_RECVONLY)) {<br>+ return s;<br>+ }<br>+ }<br>+<br>+ return NULL;<br>+}<br>+<br>+static struct ast_json *get_media_labels(struct confbridge_conference *conference,<br>+ struct ast_channel *src_chan, struct ast_channel *dest_chan, enum label_direction dir)<br>+{<br>+ struct ast_stream_topology *topology;<br>+ struct ast_stream *stream;<br>+ const char *curr_a_label;<br>+ const char *a_label = NULL;<br>+ const char *v_label = NULL;<br>+ struct ast_json *labels = ast_json_array_create();<br>+<br>+ if (!labels) {<br>+ return NULL;<br>+ }<br>+<br>+ topology = ast_channel_get_stream_topology(dir == LABEL_DIRECTION_SRC ? src_chan : dest_chan);<br>+ stream = get_stream(topology, AST_MEDIA_TYPE_AUDIO);<br>+ curr_a_label = stream ? ast_stream_get_metadata(stream, "MSID:LABEL") : NULL;<br>+ a_label = curr_a_label ?: conference->bridge->uniqueid;<br>+ ast_json_array_append(labels, ast_json_string_create(a_label));<br>+<br>+ topology = ast_channel_get_stream_topology(dir == LABEL_DIRECTION_SRC ? dest_chan : src_chan);<br>+ stream = get_stream(topology, AST_MEDIA_TYPE_VIDEO);<br>+ v_label = stream ? ast_stream_get_metadata(stream, "MSID:LABEL") : NULL;<br>+ if (v_label) {<br>+ ast_json_array_append(labels, ast_json_string_create(v_label));<br>+ }<br>+<br>+ return ast_json_pack("{s: o }", "media_source_track_labels", labels);<br>+}<br>+<br>+static void send_message(const char *msg_name, char *conf_name, struct ast_json *json_object,<br>+ struct ast_channel *chan)<br>+{<br>+ struct ast_msg_data *data_msg;<br>+ struct ast_msg_data_attribute attrs[] = {<br>+ { .type = AST_MSG_DATA_ATTR_FROM, conf_name },<br>+ { .type = AST_MSG_DATA_ATTR_CONTENT_TYPE, .value = "application/x-asterisk-confbridge-event+json"},<br>+ { .type = AST_MSG_DATA_ATTR_BODY, },<br>+ };<br>+ char *json;<br>+ int rc = 0;<br>+ struct ast_frame f;<br>+ struct ast_bridge_channel *bridge_chan;<br>+<br>+ bridge_chan = ast_channel_get_bridge_channel(chan);<br>+ if (!bridge_chan) {<br>+ /* Don't complain if we can't get the bridge_chan. The channel is probably gone. */<br>+ return;<br>+ }<br>+<br>+ json = ast_json_dump_string_format(json_object, AST_JSON_PRETTY);<br>+ if (!json) {<br>+ ast_log(LOG_ERROR, "Unable to convert json_object for %s message to string\n", msg_name);<br>+ return;<br>+ }<br>+ attrs[2].value = json;<br>+<br>+ data_msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_IN_DIALOG, attrs, ARRAY_LEN(attrs));<br>+ if (!data_msg) {<br>+ ast_log(LOG_ERROR, "Unable to create %s message for channel '%s'\n", msg_name,<br>+ ast_channel_name(chan));<br>+ ast_json_free(json);<br>+ return;<br>+ }<br>+<br>+ memset(&f, 0, sizeof(f));<br>+ f.frametype = AST_FRAME_TEXT_DATA;<br>+ f.data.ptr = data_msg;<br>+ f.datalen = ast_msg_data_get_length(data_msg);<br>+<br>+ rc = ast_bridge_channel_queue_frame(bridge_chan, &f);<br>+ ast_free(data_msg);<br>+ if (rc != 0) {<br>+ /* Don't complain if we can't send a leave message. The channel is probably gone. */<br>+ if (strcmp(confbridge_event_type_to_string(confbridge_leave_type()), msg_name) != 0) {<br>+ ast_log(LOG_ERROR, "Failed to queue %s message to '%s'\n%s\n", msg_name,<br>+ ast_channel_name(chan), json);<br>+ }<br>+ ast_json_free(json);<br>+ return;<br>+ }<br>+<br>+ ast_debug(3, "Queued %s message to '%s'\n%s\n", msg_name, ast_channel_name(chan), json);<br>+ ast_json_free(json);<br>+}<br>+<br>+static void send_event_to_participants(struct confbridge_conference *conference,<br>+ struct ast_channel *chan, struct stasis_message * msg)<br>+{<br>+ struct ast_bridge_blob *obj = stasis_message_data(msg);<br>+ struct ast_json *extras = obj->blob;<br>+ struct user_profile u_profile = {{0}};<br>+ int source_send_events = 0;<br>+ int source_echo_events = 0;<br>+ struct ast_json* json_channels = NULL;<br>+ struct confbridge_user *user;<br>+ const char *msg_name = confbridge_event_type_to_string(stasis_message_type(msg));<br>+<br>+ ast_debug(3, "Distributing %s event to participants\n", msg_name);<br>+<br>+ /* This could be a channel level event or a bridge level event */<br>+ if (chan) {<br>+ if (!conf_find_user_profile(chan, NULL, &u_profile)) {<br>+ ast_log(LOG_ERROR, "Unable to retrieve user profile for channel '%s'\n",<br>+ ast_channel_name(chan));<br>+ return;<br>+ }<br>+ source_send_events = ast_test_flag(&u_profile, USER_OPT_SEND_EVENTS);<br>+ source_echo_events = ast_test_flag(&u_profile, USER_OPT_ECHO_EVENTS);<br>+ ast_debug(3, "send_events: %d echo_events: %d for profile %s\n",<br>+ source_send_events, source_echo_events, u_profile.name);<br>+ }<br>+<br>+ /* Now send a message to the participants with the json string. */<br>+ ao2_lock(conference);<br>+ AST_LIST_TRAVERSE(&conference->active_list, user, list) {<br>+ struct ast_json *json_object;<br>+ struct ast_json* source_json_labels = NULL;<br>+<br>+ /*<br>+ * If the msg type is join, we need to capture all targets channel info so we can<br>+ * send a welcome message to the source channel with all current participants.<br>+ */<br>+ if (source_send_events && stasis_message_type(msg) == confbridge_join_type()) {<br>+ struct ast_channel_snapshot *target_snapshot;<br>+ struct ast_json *target_json_channel;<br>+ struct ast_json *target_json_labels;<br>+<br>+ target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(user->chan));<br>+ if (!target_snapshot) {<br>+ ast_log(LOG_ERROR, "Unable to get a channel snapshot for '%s'\n",<br>+ ast_channel_name(user->chan));<br>+ continue;<br>+ }<br>+<br>+ target_json_labels = get_media_labels(conference, chan, user->chan, LABEL_DIRECTION_SRC);<br>+ target_json_channel = channel_to_json(target_snapshot, extras, target_json_labels);<br>+ ao2_ref(target_snapshot, -1);<br>+ ast_json_unref(target_json_labels);<br>+<br>+ if (!json_channels) {<br>+ json_channels = ast_json_array_create();<br>+ if (!json_channels) {<br>+ ast_log(LOG_ERROR, "Unable to allocate json array\n");<br>+ ast_json_unref(target_json_channel);<br>+ ast_json_unref(target_json_labels);<br>+ return;<br>+ }<br>+ }<br>+<br>+ ast_json_array_append(json_channels, target_json_channel);<br>+ }<br>+<br>+ /* Don't send a message to the user that triggered the event. */<br>+ if (!source_echo_events && user->chan == chan) {<br>+ ast_debug(3, "Skipping queueing %s message to '%s'. Same channel.\n", msg_name,<br>+ ast_channel_name(user->chan));<br>+ continue;<br>+ }<br>+<br>+ /* Don't send a message to users in profiles not sending events. */<br>+ if (!ast_test_flag(&user->u_profile, USER_OPT_SEND_EVENTS)) {<br>+ ast_debug(3, "Skipping queueing %s message to '%s'. Not receiving events.\n", msg_name,<br>+ ast_channel_name(user->chan));<br>+ continue;<br>+ }<br>+<br>+ source_json_labels = get_media_labels(conference, chan, user->chan, LABEL_DIRECTION_DEST);<br>+ ast_json_object_update(extras, source_json_labels);<br>+<br>+ json_object = pack_snapshots(obj->bridge, obj->channel, extras, source_json_labels, msg);<br>+ ast_json_unref(source_json_labels);<br>+<br>+ if (!json_object) {<br>+ ast_log(LOG_ERROR, "Unable to convert %s message to json\n", msg_name);<br>+ continue;<br>+ }<br>+<br>+ send_message(msg_name, conference->name, json_object, user->chan);<br>+ ast_json_unref(json_object);<br>+ }<br>+ ao2_unlock(conference);<br>+<br>+ /*<br>+ * If this is a join event, send the welcome message to just the joining user<br>+ * if it's not audio-only or otherwise restricted.<br>+ */<br>+ if (source_send_events && json_channels<br>+ && stasis_message_type(msg) == confbridge_join_type()) {<br>+ struct ast_json *json_object;<br>+ struct ast_json *json_bridge;<br>+ const char *welcome_msg_name = confbridge_event_type_to_string(confbridge_welcome_type());<br>+<br>+ json_bridge = bridge_to_json(obj->bridge);<br>+ json_object = pack_bridge_and_channels(json_bridge, json_channels, msg);<br>+ if (!json_object) {<br>+ ast_log(LOG_ERROR, "Unable to convert ConfbridgeWelcome message to json\n");<br>+ return;<br>+ }<br>+ ast_json_string_set(ast_json_object_get(json_object, "type"), welcome_msg_name);<br>+<br>+ send_message(welcome_msg_name, conference->name, json_object, chan);<br>+ ast_json_unref(json_object);<br>+ }<br>+}<br>+<br> static void confbridge_publish_manager_event(<br> struct stasis_message *message,<br> struct ast_str *extra_text)<br>@@ -293,7 +616,17 @@<br> ast_assert(conference_name != NULL);<br> <br> if (blob->channel) {<br>+ struct confbridge_conference *conference = conf_find_bridge(conference_name);<br>+<br> channel_text = ast_manager_build_channel_state_string(blob->channel);<br>+<br>+ if (conference && ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {<br>+ struct ast_channel *chan = ast_channel_get_by_name(blob->channel->name);<br>+<br>+ send_event_to_participants(conference, chan, message);<br>+ ast_channel_cleanup(chan);<br>+ }<br>+ ao2_cleanup(conference);<br> }<br> <br> manager_event(EVENT_FLAG_CALL, event,<br>diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h<br>index 8329335..51ff9a4 100644<br>--- a/apps/confbridge/include/confbridge.h<br>+++ b/apps/confbridge/include/confbridge.h<br>@@ -689,4 +689,18 @@<br> * \retval -1 on error.<br> */<br> int conf_announce_channel_push(struct ast_channel *ast);<br>+<br>+/*!<br>+ * \brief Find a confbridge by name.<br>+ * \since 13.22.0<br>+ * \since 15.5.0<br>+ *<br>+ * \param confbridge_name The name to search for<br>+ *<br>+ * \return ConfBridge (which must be unreffed) or NULL.<br>+ */<br>+struct confbridge_conference *conf_find_bridge(const char *conference_name);<br>+<br>+<br>+<br> #endif<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/9294">change 9294</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/9294"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I228806ac153074f45e0b35d5236166e92e132abd </div>
<div style="display:none"> Gerrit-Change-Number: 9294 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>