<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/9294">View Change</a></p><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, 351 insertions(+), 312 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/94/9294/1</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..60b0570 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,16 @@<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 (ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {<br>+                        struct ast_channel *chan = ast_channel_get_by_name(blob->channel->name);<br>+                       send_event_to_participants(conference, chan, message);<br>+                       ast_channel_cleanup(chan);<br>+           }<br>+            ao2_ref(conference, -1);<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: newchange </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: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>