<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/10227">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  Kevin Harwell: Looks good to me, approved
  George Joseph: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">bridges:  Remove reliance on stasis caching<br><br>* The bridging core no longer uses the stasis cache for bridge<br>  snapshots.  The latest bridge snapshot is now stored on the<br>  ast_bridge structure itself.<br><br>* The following APIs are no longer available since the stasis cache<br>  is no longer used:<br>    ast_bridge_topic_cached()<br>    ast_bridge_topic_all_cached()<br><br>* A topic pool is now used for individual bridge topics.<br><br>* The ast_bridge_cache() function was removed since there's no<br>  longer a separate container of snapshots.<br><br>* A new function "ast_bridges()" was created to retrieve the<br>  container of all bridges.  Users formerly calling<br>  ast_bridge_cache() can use the new function to iterate over<br>  bridges and retrieve the latest snapshot directly from the<br>  bridge.<br><br>* The ast_bridge_snapshot_get_latest() function was renamed to<br>  ast_bridge_get_snapshot_by_uniqueid().<br><br>* A new function "ast_bridge_get_snapshot()" was created to retrieve<br>  the bridge snapshot directly from the bridge structure.<br><br>* The ast_bridge_topic_all() function now returns a normal topic<br>  not a cached one so you can't use stasis cache functions on it<br>  either.<br><br>* The ast_bridge_snapshot_type() stasis message now has the<br>  ast_bridge_snapshot_update structure as it's data.  It contains<br>  the last snapshot and the new one.<br><br>* cdr, cel, manager and ari have been updated to use the new<br>  arrangement.<br><br>Change-Id: I7049b80efa88676ce5c4666f818fa18ad1985369<br>---<br>M CHANGES<br>M UPGRADE.txt<br>M apps/confbridge/confbridge_manager.c<br>M include/asterisk/bridge.h<br>M include/asterisk/stasis_bridges.h<br>M main/Makefile<br>M main/bridge.c<br>M main/cdr.c<br>M main/cel.c<br>M main/manager_bridges.c<br>M main/stasis_bridges.c<br>M res/ari/resource_bridges.c<br>M res/res_stasis.c<br>M res/stasis/app.c<br>M tests/test_cel.c<br>15 files changed, 397 insertions(+), 340 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/CHANGES b/CHANGES</span><br><span>index 111a030..5a68001 100644</span><br><span>--- a/CHANGES</span><br><span>+++ b/CHANGES</span><br><span>@@ -35,6 +35,42 @@</span><br><span>    ast_channel_snapshot_update structure as it's data.</span><br><span>    ast_channel_snapshot_get_latest() still returns the latest snapshot.</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+Bridging</span><br><span style="color: hsl(120, 100%, 40%);">+------------------</span><br><span style="color: hsl(120, 100%, 40%);">+ * The bridging core no longer uses the stasis cache for bridge</span><br><span style="color: hsl(120, 100%, 40%);">+   snapshots.  The latest bridge snapshot is now stored on the</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge structure itself.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * The following APIs are no longer available since the stasis cache</span><br><span style="color: hsl(120, 100%, 40%);">+   is no longer used:</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_bridge_topic_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_bridge_topic_all_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * A topic pool is now used for individual bridge topics.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * The ast_bridge_cache() function was removed since there's no</span><br><span style="color: hsl(120, 100%, 40%);">+   longer a separate container of snapshots.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * A new function "ast_bridges()" was created to retrieve the</span><br><span style="color: hsl(120, 100%, 40%);">+   container of all bridges.  Users formerly calling</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge_cache() can use the new function to iterate over</span><br><span style="color: hsl(120, 100%, 40%);">+   bridges and retrieve the latest snapshot directly from the</span><br><span style="color: hsl(120, 100%, 40%);">+   bridge.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * The ast_bridge_snapshot_get_latest() function was renamed to</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge_get_snapshot_by_uniqueid().</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * A new function "ast_bridge_get_snapshot()" was created to retrieve</span><br><span style="color: hsl(120, 100%, 40%);">+   the bridge snapshot directly from the bridge structure.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * The ast_bridge_topic_all() function now returns a normal topic</span><br><span style="color: hsl(120, 100%, 40%);">+   not a cached one so you can't use stasis cache functions on it</span><br><span style="color: hsl(120, 100%, 40%);">+   either.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ * The ast_bridge_snapshot_type() stasis message now has the</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge_snapshot_update structure as it's data.  It contains</span><br><span style="color: hsl(120, 100%, 40%);">+   the last snapshot and the new one.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ------------------------------------------------------------------------------</span><br><span> --- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------</span><br><span> ------------------------------------------------------------------------------</span><br><span>diff --git a/UPGRADE.txt b/UPGRADE.txt</span><br><span>index c299d83..53e9c4a 100644</span><br><span>--- a/UPGRADE.txt</span><br><span>+++ b/UPGRADE.txt</span><br><span>@@ -58,3 +58,34 @@</span><br><span>    The ast_channel_snapshot_type() stasis message now has the</span><br><span>    ast_channel_snapshot_update structure as it's data.</span><br><span>    ast_channel_snapshot_get_latest() still returns the latest snapshot.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Applications</span><br><span style="color: hsl(120, 100%, 40%);">+ - The JabberStatus application, deprecated in Asterisk 12, has been removed.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Bridging</span><br><span style="color: hsl(120, 100%, 40%);">+ - The bridging core no longer uses the stasis cache for bridge</span><br><span style="color: hsl(120, 100%, 40%);">+   snapshots.  The latest bridge snapshot is now stored on the</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge structure itself.</span><br><span style="color: hsl(120, 100%, 40%);">+ - The following APIs are no longer available since the stasis cache</span><br><span style="color: hsl(120, 100%, 40%);">+   is no longer used:</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_bridge_topic_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_bridge_topic_all_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+ - A topic pool is now used for individual bridge topics.</span><br><span style="color: hsl(120, 100%, 40%);">+ - The ast_bridge_cache() function was removed since there's no</span><br><span style="color: hsl(120, 100%, 40%);">+   longer a separate container of snapshots.</span><br><span style="color: hsl(120, 100%, 40%);">+ - A new function "ast_bridges()" was created to retrieve the</span><br><span style="color: hsl(120, 100%, 40%);">+   container of all bridges.  Users formerly calling</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge_cache() can use the new function to iterate over</span><br><span style="color: hsl(120, 100%, 40%);">+   bridges and retrieve the latest snapshot directly from the</span><br><span style="color: hsl(120, 100%, 40%);">+   bridge.</span><br><span style="color: hsl(120, 100%, 40%);">+ - The ast_bridge_snapshot_get_latest() function was renamed to</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge_get_snapshot_by_uniqueid().</span><br><span style="color: hsl(120, 100%, 40%);">+ - A new function "ast_bridge_get_snapshot()" was created to retrieve</span><br><span style="color: hsl(120, 100%, 40%);">+   the bridge snapshot directly from the bridge structure.</span><br><span style="color: hsl(120, 100%, 40%);">+ - The ast_bridge_topic_all() function now returns a normal topic</span><br><span style="color: hsl(120, 100%, 40%);">+   not a cached one so you can't use stasis cache functions on it</span><br><span style="color: hsl(120, 100%, 40%);">+   either.</span><br><span style="color: hsl(120, 100%, 40%);">+ - The ast_bridge_snapshot_type() stasis message now has the</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_bridge_snapshot_update structure as it's data.  It contains</span><br><span style="color: hsl(120, 100%, 40%);">+   the last snapshot and the new one.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c</span><br><span>index 2d85033..b1819ca 100644</span><br><span>--- a/apps/confbridge/confbridge_manager.c</span><br><span>+++ b/apps/confbridge/confbridge_manager.c</span><br><span>@@ -712,7 +712,7 @@</span><br><span>       STASIS_MESSAGE_TYPE_INIT(confbridge_welcome_type);</span><br><span> </span><br><span>       bridge_state_router = stasis_message_router_create(</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_bridge_topic_all_cached());</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_bridge_topic_all());</span><br><span> </span><br><span>         if (!bridge_state_router) {</span><br><span>          return -1;</span><br><span>diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h</span><br><span>index f4b1df8..e4d11e8 100644</span><br><span>--- a/include/asterisk/bridge.h</span><br><span>+++ b/include/asterisk/bridge.h</span><br><span>@@ -75,6 +75,7 @@</span><br><span> #include "asterisk/dsp.h"</span><br><span> #include "asterisk/uuid.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct a02_container;</span><br><span> struct ast_bridge_technology;</span><br><span> struct ast_bridge;</span><br><span> struct ast_bridge_tech_optimizations;</span><br><span>@@ -300,6 +301,39 @@</span><br><span> AST_LIST_HEAD_NOLOCK(ast_bridge_channels_list, ast_bridge_channel);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Structure that contains a snapshot of information about a bridge</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_bridge_snapshot {</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_DECLARE_STRING_FIELDS(</span><br><span style="color: hsl(120, 100%, 40%);">+            /*! Immutable bridge UUID. */</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_STRING_FIELD(uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+           /*! Bridge technology that is handling the bridge */</span><br><span style="color: hsl(120, 100%, 40%);">+          AST_STRING_FIELD(technology);</span><br><span style="color: hsl(120, 100%, 40%);">+         /*! Bridge subclass that is handling the bridge */</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_STRING_FIELD(subclass);</span><br><span style="color: hsl(120, 100%, 40%);">+           /*! Creator of the bridge */</span><br><span style="color: hsl(120, 100%, 40%);">+          AST_STRING_FIELD(creator);</span><br><span style="color: hsl(120, 100%, 40%);">+            /*! Name given to the bridge by its creator */</span><br><span style="color: hsl(120, 100%, 40%);">+                AST_STRING_FIELD(name);</span><br><span style="color: hsl(120, 100%, 40%);">+               /*! Unique ID of the channel providing video, if one exists */</span><br><span style="color: hsl(120, 100%, 40%);">+                AST_STRING_FIELD(video_source_id);</span><br><span style="color: hsl(120, 100%, 40%);">+    );</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! AO2 container of bare channel uniqueid strings participating in the bridge.</span><br><span style="color: hsl(120, 100%, 40%);">+        * Allocated from ast_str_container_alloc() */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ao2_container *channels;</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Bridge flags to tweak behavior */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_flags feature_flags;</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Bridge capabilities */</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t capabilities;</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Number of channels participating in the bridge */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int num_channels;</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Number of active channels in the bridge. */</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int num_active;</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! The video mode of the bridge */</span><br><span style="color: hsl(120, 100%, 40%);">+   enum ast_bridge_video_mode_type video_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Structure that contains information about a bridge</span><br><span>  */</span><br><span> struct ast_bridge {</span><br><span>@@ -312,7 +346,7 @@</span><br><span>   /*! Private information unique to the bridge technology */</span><br><span>   void *tech_pvt;</span><br><span>      /*! Per-bridge topics */</span><br><span style="color: hsl(0, 100%, 40%);">-        struct stasis_cp_single *topics;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct stasis_topic *topic;</span><br><span>  /*! Call ID associated with the bridge */</span><br><span>    ast_callid callid;</span><br><span>   /*! Linked list of channels participating in the bridge */</span><br><span>@@ -358,12 +392,27 @@</span><br><span> </span><br><span>       /*! Type mapping used for media routing */</span><br><span>   struct ast_vector_int media_types;</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Current bridge snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_bridge_snapshot *current_snapshot;</span><br><span> };</span><br><span> </span><br><span> /*! \brief Bridge base class virtual method table. */</span><br><span> extern struct ast_bridge_methods ast_bridge_base_v_table;</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns the global bridges container</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval a pointer to the bridges container success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note You must use ao2_ref(<container>, -1) when done with it</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \warning You must not attempt to modify the container returned.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ao2_container *ast_bridges(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Create a new base class bridge</span><br><span>  *</span><br><span>  * \param capabilities The capabilities that we require to be used on the bridge</span><br><span>diff --git a/include/asterisk/stasis_bridges.h b/include/asterisk/stasis_bridges.h</span><br><span>index a455a5b..4d80955 100644</span><br><span>--- a/include/asterisk/stasis_bridges.h</span><br><span>+++ b/include/asterisk/stasis_bridges.h</span><br><span>@@ -31,37 +31,9 @@</span><br><span> #include "asterisk/bridge.h"</span><br><span> #include "asterisk/pbx.h"</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Structure that contains a snapshot of information about a bridge</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_bridge_snapshot {</span><br><span style="color: hsl(0, 100%, 40%);">-  AST_DECLARE_STRING_FIELDS(</span><br><span style="color: hsl(0, 100%, 40%);">-              /*! Immutable bridge UUID. */</span><br><span style="color: hsl(0, 100%, 40%);">-           AST_STRING_FIELD(uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">-             /*! Bridge technology that is handling the bridge */</span><br><span style="color: hsl(0, 100%, 40%);">-            AST_STRING_FIELD(technology);</span><br><span style="color: hsl(0, 100%, 40%);">-           /*! Bridge subclass that is handling the bridge */</span><br><span style="color: hsl(0, 100%, 40%);">-              AST_STRING_FIELD(subclass);</span><br><span style="color: hsl(0, 100%, 40%);">-             /*! Creator of the bridge */</span><br><span style="color: hsl(0, 100%, 40%);">-            AST_STRING_FIELD(creator);</span><br><span style="color: hsl(0, 100%, 40%);">-              /*! Name given to the bridge by its creator */</span><br><span style="color: hsl(0, 100%, 40%);">-          AST_STRING_FIELD(name);</span><br><span style="color: hsl(0, 100%, 40%);">-         /*! Unique ID of the channel providing video, if one exists */</span><br><span style="color: hsl(0, 100%, 40%);">-          AST_STRING_FIELD(video_source_id);</span><br><span style="color: hsl(0, 100%, 40%);">-      );</span><br><span style="color: hsl(0, 100%, 40%);">-      /*! AO2 container of bare channel uniqueid strings participating in the bridge.</span><br><span style="color: hsl(0, 100%, 40%);">-  * Allocated from ast_str_container_alloc() */</span><br><span style="color: hsl(0, 100%, 40%);">-  struct ao2_container *channels;</span><br><span style="color: hsl(0, 100%, 40%);">- /*! Bridge flags to tweak behavior */</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ast_flags feature_flags;</span><br><span style="color: hsl(0, 100%, 40%);">- /*! Bridge capabilities */</span><br><span style="color: hsl(0, 100%, 40%);">-      uint32_t capabilities;</span><br><span style="color: hsl(0, 100%, 40%);">-  /*! Number of channels participating in the bridge */</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned int num_channels;</span><br><span style="color: hsl(0, 100%, 40%);">-      /*! Number of active channels in the bridge. */</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int num_active;</span><br><span style="color: hsl(0, 100%, 40%);">-        /*! The video mode of the bridge */</span><br><span style="color: hsl(0, 100%, 40%);">-     enum ast_bridge_video_mode_type video_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_bridge_snapshot_update {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_bridge_snapshot *old_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_bridge_snapshot *new_snapshot;</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span>@@ -101,22 +73,6 @@</span><br><span> </span><br><span> /*!</span><br><span>  * \since 12</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief A topic which publishes the events for a particular bridge.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \ref ast_bridge_snapshot messages are replaced with stasis_cache_update</span><br><span style="color: hsl(0, 100%, 40%);">- * messages.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * If the given \a bridge is \c NULL, ast_bridge_topic_all_cached() is returned.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \param bridge Bridge for which to get a topic or \c NULL.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval Topic for bridge's events.</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval ast_bridge_topic_all() if \a bridge is \c NULL.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 12</span><br><span>  * \brief A topic which publishes the events for all bridges.</span><br><span>  * \retval Topic for all bridge events.</span><br><span>  */</span><br><span>@@ -124,22 +80,6 @@</span><br><span> </span><br><span> /*!</span><br><span>  * \since 12</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief A caching topic which caches \ref ast_bridge_snapshot messages from</span><br><span style="color: hsl(0, 100%, 40%);">- * ast_bridge_events_all(void).</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval Caching topic for all bridge events.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_topic *ast_bridge_topic_all_cached(void);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 12</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Backend cache for ast_bridge_topic_all_cached().</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval Cache of \ref ast_bridge_snapshot.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_cache *ast_bridge_cache(void);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 12</span><br><span>  * \brief Publish the state of a bridge</span><br><span>  *</span><br><span>  * \pre Bridge is locked</span><br><span>@@ -490,18 +430,32 @@</span><br><span> struct stasis_message_type *ast_attended_transfer_type(void);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Returns the most recent snapshot for the bridge.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns the current snapshot for the bridge.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.0</span><br><span>  *</span><br><span>  * The returned pointer is AO2 managed, so ao2_cleanup() when you're done.</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * \param bridge_id Uniqueid of the bridge for which to get the snapshot.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bridge_id Uniqueid of the bridge from which to get the snapshot.</span><br><span>  * \return Most recent snapshot. ao2_cleanup() when done.</span><br><span style="color: hsl(0, 100%, 40%);">- * \return \c NULL if channel isn't in cache.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return \c NULL if bridge or snapshot doesn't exist.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_bridge_snapshot *ast_bridge_get_snapshot_by_uniqueid(</span><br><span>  const char *bridge_id);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Returns the current snapshot for the bridge.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.0</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The returned pointer is AO2 managed, so ao2_cleanup() when you're done.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bridge The bridge from which to get the snapshot.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Most recent snapshot. ao2_cleanup() when done.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return \c NULL if there isn't a snapshot.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_bridge_snapshot *ast_bridge_get_snapshot(</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_bridge *bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \internal</span><br><span>  * \brief Initialize the topics for a single bridge.</span><br><span>  * \return 0 on success.</span><br><span>@@ -511,6 +465,15 @@</span><br><span> </span><br><span> /*!</span><br><span>  * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Publish destroy then cleanup topics.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bridge The bridge to clean up</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void bridge_topics_destroy(struct ast_bridge *bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span>  * \brief Initialize the stasis bridging topic and message types</span><br><span>  * \retval 0 on success</span><br><span>  * \retval -1 on failure</span><br><span>diff --git a/main/Makefile b/main/Makefile</span><br><span>index 1cb2c25..a22a1ad 100644</span><br><span>--- a/main/Makefile</span><br><span>+++ b/main/Makefile</span><br><span>@@ -167,6 +167,7 @@</span><br><span> sched.o: _ASTCFLAGS+=$(call get_menuselect_cflags,DEBUG_SCHEDULER DUMP_SCHEDULER)</span><br><span> tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) -Wno-deprecated-declarations</span><br><span> uuid.o: _ASTCFLAGS+=$(UUID_INCLUDE)</span><br><span style="color: hsl(120, 100%, 40%);">+stasis.o: _ASTCFLAGS+=$(call get_menuselect_cflags,AO2_DEBUG)</span><br><span> </span><br><span> </span><br><span> OBJS:=$(sort $(OBJS))</span><br><span>diff --git a/main/bridge.c b/main/bridge.c</span><br><span>index a65927d..1bee2e6 100644</span><br><span>--- a/main/bridge.c</span><br><span>+++ b/main/bridge.c</span><br><span>@@ -171,6 +171,11 @@</span><br><span> /*! Bridge manager controller. */</span><br><span> static struct bridge_manager_controller *bridge_manager;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ao2_container *ast_bridges(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return ao2_bump(bridges);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \internal</span><br><span>  * \brief Request service for a bridge from the bridge manager.</span><br><span>@@ -650,25 +655,6 @@</span><br><span>      }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_message *create_bridge_snapshot_message(struct ast_bridge *bridge)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!ast_bridge_snapshot_type()) {</span><br><span style="color: hsl(0, 100%, 40%);">-              return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_bridge_lock(bridge);</span><br><span style="color: hsl(0, 100%, 40%);">-        snapshot = ast_bridge_snapshot_create(bridge);</span><br><span style="color: hsl(0, 100%, 40%);">-  ast_bridge_unlock(bridge);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">-                return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return stasis_message_create(ast_bridge_snapshot_type(), snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static void destroy_bridge(void *obj)</span><br><span> {</span><br><span>   struct ast_bridge *bridge = obj;</span><br><span>@@ -677,17 +663,7 @@</span><br><span>              bridge->uniqueid, bridge->v_table->name);</span><br><span> </span><br><span>       if (bridge->construction_completed) {</span><br><span style="color: hsl(0, 100%, 40%);">-                RAII_VAR(struct stasis_message *, clear_msg, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                clear_msg = create_bridge_snapshot_message(bridge);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (clear_msg) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                      msg = stasis_cache_clear_create(clear_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (msg) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              stasis_publish(ast_bridge_topic(bridge), msg);</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(120, 100%, 40%);">+             bridge_topics_destroy(bridge);</span><br><span>       }</span><br><span> </span><br><span>        /* Do any pending actions in the context of destruction. */</span><br><span>@@ -726,9 +702,8 @@</span><br><span> </span><br><span>        cleanup_video_mode(bridge);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- stasis_cp_single_unsubscribe(bridge->topics);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>     ast_string_field_free_memory(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(bridge->current_snapshot);</span><br><span> }</span><br><span> </span><br><span> struct ast_bridge *bridge_register(struct ast_bridge *bridge)</span><br><span>@@ -2008,6 +1983,9 @@</span><br><span> {</span><br><span>     struct ast_bridge_channel *bridge_channel;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        ast_debug(1, "Removing channel %s from bridge %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_channel_name(chan), bridge->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      ast_bridge_lock(bridge);</span><br><span> </span><br><span>         /* Try to find the channel that we want to remove */</span><br><span>@@ -5071,43 +5049,13 @@</span><br><span>       return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static char *complete_bridge_stasis(const char *word)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     int wordlen = strlen(word);</span><br><span style="color: hsl(0, 100%, 40%);">-     struct ao2_container *cached_bridges;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ao2_iterator iter;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct stasis_message *msg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     cached_bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!cached_bridges) {</span><br><span style="color: hsl(0, 100%, 40%);">-          return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       iter = ao2_iterator_init(cached_bridges, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!strncasecmp(word, snapshot->uniqueid, wordlen)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (ast_cli_completion_add(ast_strdup(snapshot->uniqueid))) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ao2_ref(msg, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                               break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-       ao2_iterator_destroy(&iter);</span><br><span style="color: hsl(0, 100%, 40%);">-        ao2_ref(cached_bridges, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static char *handle_bridge_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span> #define FORMAT_HDR "%-36s %5s %-15s %s\n"</span><br><span> #define FORMAT_ROW "%-36s %5u %-15s %s\n"</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   RAII_VAR(struct ao2_container *, cached_bridges, NULL, ao2_cleanup);</span><br><span>         struct ao2_iterator iter;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct stasis_message *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_bridge *bridge;</span><br><span> </span><br><span>       switch (cmd) {</span><br><span>       case CLI_INIT:</span><br><span>@@ -5120,25 +5068,23 @@</span><br><span>             return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   cached_bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!cached_bridges) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_cli(a->fd, "Failed to retrieve cached bridges\n");</span><br><span style="color: hsl(0, 100%, 40%);">-             return CLI_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    ast_cli(a->fd, FORMAT_HDR, "Bridge-ID", "Chans", "Type", "Technology");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  iter = ao2_iterator_init(cached_bridges, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+      iter = ao2_iterator_init(bridges, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (; (bridge = ao2_iterator_next(&iter)); ao2_ref(bridge, -1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct ast_bridge_snapshot *snapshot = ast_bridge_get_snapshot(bridge);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-             ast_cli(a->fd, FORMAT_ROW,</span><br><span style="color: hsl(0, 100%, 40%);">-                   snapshot->uniqueid,</span><br><span style="color: hsl(0, 100%, 40%);">-                  snapshot->num_channels,</span><br><span style="color: hsl(0, 100%, 40%);">-                      S_OR(snapshot->subclass, "<unknown>"),</span><br><span style="color: hsl(0, 100%, 40%);">-                       S_OR(snapshot->technology, "<unknown>"));</span><br><span style="color: hsl(120, 100%, 40%);">+          if (snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_cli(a->fd, FORMAT_ROW,</span><br><span style="color: hsl(120, 100%, 40%);">+                         snapshot->uniqueid,</span><br><span style="color: hsl(120, 100%, 40%);">+                                snapshot->num_channels,</span><br><span style="color: hsl(120, 100%, 40%);">+                            S_OR(snapshot->subclass, "<unknown>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                             S_OR(snapshot->technology, "<unknown>"));</span><br><span style="color: hsl(120, 100%, 40%);">+                  ao2_ref(snapshot, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span>    }</span><br><span>    ao2_iterator_destroy(&iter);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   return CLI_SUCCESS;</span><br><span> </span><br><span> #undef FORMAT_HDR</span><br><span>@@ -5165,7 +5111,6 @@</span><br><span> </span><br><span> static char *handle_bridge_show_specific(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);</span><br><span>   struct ast_bridge_snapshot *snapshot;</span><br><span> </span><br><span>    switch (cmd) {</span><br><span>@@ -5177,7 +5122,7 @@</span><br><span>               return NULL;</span><br><span>         case CLI_GENERATE:</span><br><span>           if (a->pos == 2) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   return complete_bridge_stasis(a->word);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return complete_bridge_live(a->word);</span><br><span>             }</span><br><span>            return NULL;</span><br><span>         }</span><br><span>@@ -5186,18 +5131,17 @@</span><br><span>          return CLI_SHOWUSAGE;</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), a->argv[2]);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+   snapshot = ast_bridge_get_snapshot_by_uniqueid(a->argv[2]);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!snapshot) {</span><br><span>             ast_cli(a->fd, "Bridge '%s' not found\n", a->argv[2]);</span><br><span>               return CLI_SUCCESS;</span><br><span>  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       snapshot = stasis_message_data(msg);</span><br><span>         ast_cli(a->fd, "Id: %s\n", snapshot->uniqueid);</span><br><span>      ast_cli(a->fd, "Type: %s\n", S_OR(snapshot->subclass, "<unknown>"));</span><br><span>         ast_cli(a->fd, "Technology: %s\n", S_OR(snapshot->technology, "<unknown>"));</span><br><span>         ast_cli(a->fd, "Num-Channels: %u\n", snapshot->num_channels);</span><br><span>        ao2_callback(snapshot->channels, OBJ_NODATA, bridge_show_specific_print_channel, a);</span><br><span style="color: hsl(120, 100%, 40%);">+       ao2_ref(snapshot, -1);</span><br><span> </span><br><span>   return CLI_SUCCESS;</span><br><span> }</span><br><span>diff --git a/main/cdr.c b/main/cdr.c</span><br><span>index 2e3b205..462c3e6 100644</span><br><span>--- a/main/cdr.c</span><br><span>+++ b/main/cdr.c</span><br><span>@@ -4288,7 +4288,7 @@</span><br><span>        if (!channel_subscription) {</span><br><span>                 return -1;</span><br><span>   }</span><br><span style="color: hsl(0, 100%, 40%);">-       bridge_subscription = stasis_forward_all(ast_bridge_topic_all_cached(), cdr_topic);</span><br><span style="color: hsl(120, 100%, 40%);">+   bridge_subscription = stasis_forward_all(ast_bridge_topic_all(), cdr_topic);</span><br><span>         if (!bridge_subscription) {</span><br><span>          return -1;</span><br><span>   }</span><br><span>diff --git a/main/cel.c b/main/cel.c</span><br><span>index 242aeff..95376db 100644</span><br><span>--- a/main/cel.c</span><br><span>+++ b/main/cel.c</span><br><span>@@ -1449,7 +1449,7 @@</span><br><span>       }</span><br><span> </span><br><span>        cel_bridge_forwarder = stasis_forward_all(</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_bridge_topic_all_cached(),</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_bridge_topic_all(),</span><br><span>              cel_aggregation_topic);</span><br><span>      if (!cel_bridge_forwarder) {</span><br><span>                 return -1;</span><br><span>diff --git a/main/manager_bridges.c b/main/manager_bridges.c</span><br><span>index 4f2cb35..d49b783 100644</span><br><span>--- a/main/manager_bridges.c</span><br><span>+++ b/main/manager_bridges.c</span><br><span>@@ -330,22 +330,15 @@</span><br><span>                                  struct stasis_message *message)</span><br><span> {</span><br><span>     RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct stasis_cache_update *update;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct ast_bridge_snapshot *old_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_bridge_snapshot *new_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_bridge_snapshot_update *update;</span><br><span>   size_t i;</span><br><span> </span><br><span>        update = stasis_message_data(message);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      ast_assert(ast_bridge_snapshot_type() == update->type);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      old_snapshot = stasis_message_data(update->old_snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">-    new_snapshot = stasis_message_data(update->new_snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) {</span><br><span>                RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                event = bridge_monitors[i](old_snapshot, new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+               event = bridge_monitors[i](update->old_snapshot, update->new_snapshot);</span><br><span>                if (!event) {</span><br><span>                        continue;</span><br><span>            }</span><br><span>@@ -354,7 +347,7 @@</span><br><span>              if (!bridge_event_string) {</span><br><span>                  bridge_event_string =</span><br><span>                                ast_manager_build_bridge_state_string(</span><br><span style="color: hsl(0, 100%, 40%);">-                                  new_snapshot ? new_snapshot : old_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+                                  update->new_snapshot ? update->new_snapshot : update->old_snapshot);</span><br><span>                        if (!bridge_event_string) {</span><br><span>                          return;</span><br><span>                      }</span><br><span>@@ -446,26 +439,30 @@</span><br><span>            ast_str_buffer(channel_text));</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int filter_bridge_type_cb(void *obj, void *arg, int flags)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       char *bridge_type = arg;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);</span><br><span style="color: hsl(0, 100%, 40%);">-        /* unlink all the snapshots that do not match the bridge type */</span><br><span style="color: hsl(0, 100%, 40%);">-        return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct bridge_list_data {</span><br><span style="color: hsl(0, 100%, 40%);">-      const char *id_text;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_str *id_text;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *type_filter;</span><br><span>     int count;</span><br><span> };</span><br><span> </span><br><span> static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_bridge *bridge = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+      RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_get_snapshot(bridge), ao2_cleanup);</span><br><span>      struct mansession *s = arg;</span><br><span>  struct bridge_list_data *list_data = data;</span><br><span style="color: hsl(0, 100%, 40%);">-      RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_str * bridge_info;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     if (!snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(list_data->type_filter)</span><br><span style="color: hsl(120, 100%, 40%);">+               && strcmp(list_data->type_filter, snapshot->technology)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bridge_info = ast_manager_build_bridge_state_string(snapshot);</span><br><span>       if (!bridge_info) {</span><br><span>          return 0;</span><br><span>    }</span><br><span>@@ -475,9 +472,12 @@</span><br><span>             "%s"</span><br><span>               "%s"</span><br><span>               "\r\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               list_data->id_text,</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_str_buffer(list_data->id_text),</span><br><span>               ast_str_buffer(bridge_info));</span><br><span>        ++list_data->count;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_free(bridge_info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -485,41 +485,37 @@</span><br><span> {</span><br><span>      const char *id = astman_get_header(m, "ActionID");</span><br><span>         const char *type_filter = astman_get_header(m, "BridgeType");</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);</span><br><span style="color: hsl(0, 100%, 40%);">-     RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-   struct bridge_list_data list_data;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ao2_container *bridges;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bridge_list_data list_data = { 0 };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  if (!id_text) {</span><br><span style="color: hsl(0, 100%, 40%);">-         astman_send_error(s, m, "Internal error");</span><br><span style="color: hsl(0, 100%, 40%);">-            return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!ast_strlen_zero(id)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       bridges = stasis_cache_dump(ast_bridge_cache(), ast_bridge_snapshot_type());</span><br><span style="color: hsl(120, 100%, 40%);">+  bridges = ast_bridges();</span><br><span>     if (!bridges) {</span><br><span>              astman_send_error(s, m, "Internal error");</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   astman_send_listack(s, m, "Bridge listing will follow", "start");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!ast_strlen_zero(type_filter)) {</span><br><span style="color: hsl(0, 100%, 40%);">-            char *type_filter_dup = ast_strdupa(type_filter);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK,</span><br><span style="color: hsl(0, 100%, 40%);">-                   filter_bridge_type_cb, type_filter_dup);</span><br><span style="color: hsl(120, 100%, 40%);">+      list_data.id_text = ast_str_create(128);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!list_data.id_text) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_ref(bridges, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+         astman_send_error(s, m, "Internal error");</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   list_data.id_text = ast_str_buffer(id_text);</span><br><span style="color: hsl(0, 100%, 40%);">-    list_data.count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_str_set(&list_data.id_text, 0, "ActionID: %s\r\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     list_data.type_filter = type_filter;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        astman_send_listack(s, m, "Bridge listing will follow", "start");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, &list_data);</span><br><span> </span><br><span>     astman_send_list_complete_start(s, m, "BridgeListComplete", list_data.count);</span><br><span>      astman_send_list_complete_end(s);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(list_data.id_text);</span><br><span style="color: hsl(120, 100%, 40%);">+  ao2_ref(bridges, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -550,7 +546,7 @@</span><br><span>             "%s"</span><br><span>               "%s"</span><br><span>               "\r\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               list_data->id_text,</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_str_buffer(list_data->id_text),</span><br><span>               ast_str_buffer(channel_text));</span><br><span>       ++list_data->count;</span><br><span>       return 0;</span><br><span>@@ -560,43 +556,39 @@</span><br><span> {</span><br><span>       const char *id = astman_get_header(m, "ActionID");</span><br><span>         const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);</span><br><span style="color: hsl(0, 100%, 40%);">-     RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);</span><br><span>   RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_bridge_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct bridge_list_data list_data;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!id_text) {</span><br><span style="color: hsl(0, 100%, 40%);">-         astman_send_error(s, m, "Internal error");</span><br><span style="color: hsl(0, 100%, 40%);">-            return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bridge_list_data list_data = { 0 };</span><br><span> </span><br><span>       if (ast_strlen_zero(bridge_uniqueid)) {</span><br><span>              astman_send_error(s, m, "BridgeUniqueid must be provided");</span><br><span>                return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!ast_strlen_zero(id)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       msg = stasis_cache_get(ast_bridge_cache(), ast_bridge_snapshot_type(), bridge_uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+   snapshot = ast_bridge_get_snapshot_by_uniqueid(bridge_uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!snapshot) {</span><br><span>             astman_send_error(s, m, "Specified BridgeUniqueid not found");</span><br><span>             return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   snapshot = stasis_message_data(msg);</span><br><span>         bridge_info = ast_manager_build_bridge_state_string(snapshot);</span><br><span>       if (!bridge_info) {</span><br><span>          astman_send_error(s, m, "Internal error");</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ list_data.id_text = ast_str_create(128);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!list_data.id_text) {</span><br><span style="color: hsl(120, 100%, 40%);">+             astman_send_error(s, m, "Internal error");</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_str_set(&list_data.id_text, 0, "ActionID: %s\r\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  astman_send_listack(s, m, "Bridge channel listing will follow", "start");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       list_data.id_text = ast_str_buffer(id_text);</span><br><span style="color: hsl(0, 100%, 40%);">-    list_data.count = 0;</span><br><span>         ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, &list_data);</span><br><span> </span><br><span>       astman_send_list_complete_start(s, m, "BridgeInfoComplete", list_data.count);</span><br><span>@@ -604,6 +596,7 @@</span><br><span>                astman_append(s, "%s", ast_str_buffer(bridge_info));</span><br><span>       }</span><br><span>    astman_send_list_complete_end(s);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_free(list_data.id_text);</span><br><span> </span><br><span>     return 0;</span><br><span> }</span><br><span>@@ -703,7 +696,7 @@</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   bridge_topic = ast_bridge_topic_all_cached();</span><br><span style="color: hsl(120, 100%, 40%);">+ bridge_topic = ast_bridge_topic_all();</span><br><span>       if (!bridge_topic) {</span><br><span>                 return -1;</span><br><span>   }</span><br><span>@@ -718,7 +711,7 @@</span><br><span>              return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ret |= stasis_message_router_add_cache_update(bridge_state_router,</span><br><span style="color: hsl(120, 100%, 40%);">+    ret |= stasis_message_router_add(bridge_state_router,</span><br><span>                ast_bridge_snapshot_type(), bridge_snapshot_update, NULL);</span><br><span> </span><br><span>       ret |= stasis_message_router_add(bridge_state_router,</span><br><span>diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c</span><br><span>index 42bf6bc..bed28ba 100644</span><br><span>--- a/main/stasis_bridges.c</span><br><span>+++ b/main/stasis_bridges.c</span><br><span>@@ -155,7 +155,8 @@</span><br><span>         struct stasis_message *msg,</span><br><span>  const struct stasis_message_sanitizer *sanitize);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_cp_all *bridge_cache_all;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_topic *bridge_topic_all;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_topic_pool *bridge_topic_pool;</span><br><span> </span><br><span> /*!</span><br><span>  * @{ \brief Define bridge message types.</span><br><span>@@ -175,33 +176,9 @@</span><br><span>       .to_ami = attended_transfer_to_ami);</span><br><span> /*! @} */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_cache *ast_bridge_cache(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       return stasis_cp_all_cache(bridge_cache_all);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct stasis_topic *ast_bridge_topic_all(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  return stasis_cp_all_topic(bridge_cache_all);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_topic *ast_bridge_topic_all_cached(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   return stasis_cp_all_topic_cached(bridge_cache_all);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int bridge_topics_init(struct ast_bridge *bridge)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_strlen_zero(bridge->uniqueid)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_log(LOG_ERROR, "Bridge id initialization required\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       bridge->topics = stasis_cp_single_create(bridge_cache_all,</span><br><span style="color: hsl(0, 100%, 40%);">-           bridge->uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!bridge->topics) {</span><br><span style="color: hsl(0, 100%, 40%);">-               return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     return bridge_topic_all;</span><br><span> }</span><br><span> </span><br><span> struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)</span><br><span>@@ -210,16 +187,7 @@</span><br><span>                 return ast_bridge_topic_all();</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return stasis_cp_single_topic(bridge->topics);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!bridge) {</span><br><span style="color: hsl(0, 100%, 40%);">-          return ast_bridge_topic_all_cached();</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return stasis_cp_single_topic_cached(bridge->topics);</span><br><span style="color: hsl(120, 100%, 40%);">+      return bridge->topic;</span><br><span> }</span><br><span> </span><br><span> /*! \brief Destructor for bridge snapshots */</span><br><span>@@ -292,24 +260,106 @@</span><br><span>  return snapshot;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void ast_bridge_publish_state(struct ast_bridge *bridge)</span><br><span style="color: hsl(120, 100%, 40%);">+static void bridge_snapshot_update_dtor(void *obj)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      struct ast_bridge_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct stasis_message *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_bridge_snapshot_update *update = obj;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    if (!ast_bridge_snapshot_type()) {</span><br><span style="color: hsl(0, 100%, 40%);">-              return;</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_debug(3, "Update: %p  Old: %s  New: %s\n", update,</span><br><span style="color: hsl(120, 100%, 40%);">+              update->old_snapshot ? update->old_snapshot->uniqueid : "<none>",</span><br><span style="color: hsl(120, 100%, 40%);">+            update->new_snapshot ? update->new_snapshot->uniqueid : "<none>");</span><br><span style="color: hsl(120, 100%, 40%);">+   ao2_cleanup(update->old_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(update->new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_bridge_snapshot_update *bridge_snapshot_update_create(</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_bridge_snapshot *old, struct ast_bridge_snapshot *new)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_bridge_snapshot_update *update;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  update = ao2_alloc_options(sizeof(*update), bridge_snapshot_update_dtor,</span><br><span style="color: hsl(120, 100%, 40%);">+                      AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!update) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span>         }</span><br><span style="color: hsl(120, 100%, 40%);">+     update->old_snapshot = ao2_bump(old);</span><br><span style="color: hsl(120, 100%, 40%);">+      update->new_snapshot = ao2_bump(new);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_debug(3, "Update: %p  Old: %s  New: %s\n", update,</span><br><span style="color: hsl(120, 100%, 40%);">+              update->old_snapshot ? update->old_snapshot->uniqueid : "<none>",</span><br><span style="color: hsl(120, 100%, 40%);">+            update->new_snapshot ? update->new_snapshot->uniqueid : "<none>");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return update;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int bridge_topics_init(struct ast_bridge *bridge)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_strlen_zero(bridge->uniqueid)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "Bridge id initialization required\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bridge->topic = stasis_topic_pool_get_topic(bridge_topic_pool, bridge->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!bridge->topic) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void bridge_topics_destroy(struct ast_bridge *bridge)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_bridge_snapshot_update *update;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct stasis_message *msg;</span><br><span> </span><br><span>      ast_assert(bridge != NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- snapshot = ast_bridge_snapshot_create(bridge);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!bridge->current_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+           bridge->current_snapshot = ast_bridge_snapshot_create(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!bridge->current_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   update = bridge_snapshot_update_create(bridge->current_snapshot, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!update) {</span><br><span>               return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">-      ao2_ref(snapshot, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        msg = stasis_message_create(ast_bridge_snapshot_type(), update);</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_ref(update, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   stasis_publish(ast_bridge_topic(bridge), msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        ao2_ref(msg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   stasis_topic_pool_delete_topic(bridge_topic_pool, stasis_topic_name(ast_bridge_topic(bridge)));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_bridge_publish_state(struct ast_bridge *bridge)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_bridge_snapshot *new_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_bridge_snapshot_update *update;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct stasis_message *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_assert(bridge != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ new_snapshot = ast_bridge_snapshot_create(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   update = bridge_snapshot_update_create(bridge->current_snapshot, new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* There may not have been an old snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(bridge->current_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+     bridge->current_snapshot = new_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!update) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msg = stasis_message_create(ast_bridge_snapshot_type(), update);</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_ref(update, -1);</span><br><span>         if (!msg) {</span><br><span>          return;</span><br><span>      }</span><br><span>@@ -321,11 +371,20 @@</span><br><span> static void bridge_publish_state_from_blob(struct ast_bridge *bridge,</span><br><span>   struct ast_bridge_blob *obj)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_bridge_snapshot_update *update;</span><br><span>   struct stasis_message *msg;</span><br><span> </span><br><span>      ast_assert(obj != NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    msg = stasis_message_create(ast_bridge_snapshot_type(), obj->bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+      update = bridge_snapshot_update_create(bridge->current_snapshot, obj->bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+  ao2_cleanup(bridge->current_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+     bridge->current_snapshot = ao2_bump(obj->bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!update) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msg = stasis_message_create(ast_bridge_snapshot_type(), update);</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_ref(update, -1);</span><br><span>         if (!msg) {</span><br><span>          return;</span><br><span>      }</span><br><span>@@ -1250,35 +1309,37 @@</span><br><span>  ao2_ref(msg, -1);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(const char *uniqueid)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_bridge_snapshot *ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct stasis_message *message;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_bridge *bridge;</span><br><span>   struct ast_bridge_snapshot *snapshot;</span><br><span> </span><br><span>    ast_assert(!ast_strlen_zero(uniqueid));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     message = stasis_cache_get(ast_bridge_cache(),</span><br><span style="color: hsl(0, 100%, 40%);">-                  ast_bridge_snapshot_type(),</span><br><span style="color: hsl(0, 100%, 40%);">-                     uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!message) {</span><br><span style="color: hsl(120, 100%, 40%);">+       bridge = ast_bridge_find_by_id(uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bridge) {</span><br><span>               return NULL;</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       snapshot = ao2_bump(stasis_message_data(message));</span><br><span style="color: hsl(0, 100%, 40%);">-      ao2_ref(message, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_bridge_lock(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+      snapshot = ao2_bump(bridge->current_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_bridge_unlock(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+    ao2_ref(bridge, -1);</span><br><span> </span><br><span>     return snapshot;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief snapshot ID getter for caching topic */</span><br><span style="color: hsl(0, 100%, 40%);">-static const char *bridge_snapshot_get_id(struct stasis_message *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_bridge_snapshot *ast_bridge_get_snapshot(struct ast_bridge *bridge)</span><br><span> {</span><br><span>        struct ast_bridge_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-   if (stasis_message_type(msg) != ast_bridge_snapshot_type()) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!bridge) {</span><br><span>               return NULL;</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-       snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-    return snapshot->uniqueid;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_bridge_lock(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+      snapshot = ao2_bump(bridge->current_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_bridge_unlock(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return snapshot;</span><br><span> }</span><br><span> </span><br><span> static void stasis_bridging_cleanup(void)</span><br><span>@@ -1290,8 +1351,10 @@</span><br><span>      STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);</span><br><span>        STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    ao2_cleanup(bridge_cache_all);</span><br><span style="color: hsl(0, 100%, 40%);">-  bridge_cache_all = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_cleanup(bridge_topic_pool);</span><br><span style="color: hsl(120, 100%, 40%);">+       bridge_topic_pool = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_cleanup(bridge_topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+        bridge_topic_all = NULL;</span><br><span> }</span><br><span> </span><br><span> int ast_stasis_bridging_init(void)</span><br><span>@@ -1300,10 +1363,12 @@</span><br><span> </span><br><span>        ast_register_cleanup(stasis_bridging_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      bridge_cache_all = stasis_cp_all_create("ast_bridge_topic_all",</span><br><span style="color: hsl(0, 100%, 40%);">-               bridge_snapshot_get_id);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!bridge_cache_all) {</span><br><span style="color: hsl(120, 100%, 40%);">+      bridge_topic_all = stasis_topic_create("ast_bridge_topic_all");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bridge_topic_all) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     bridge_topic_pool = stasis_topic_pool_create(bridge_topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!bridge_topic_pool) {</span><br><span>            return -1;</span><br><span>   }</span><br><span> </span><br><span>diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c</span><br><span>index 3c0eeb7..33e4cd1 100644</span><br><span>--- a/res/ari/resource_bridges.c</span><br><span>+++ b/res/ari/resource_bridges.c</span><br><span>@@ -65,7 +65,7 @@</span><br><span>       bridge = stasis_app_bridge_find_by_id(bridge_id);</span><br><span>    if (bridge == NULL) {</span><br><span>                RAII_VAR(struct ast_bridge_snapshot *, snapshot,</span><br><span style="color: hsl(0, 100%, 40%);">-                        ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_bridge_get_snapshot_by_uniqueid(bridge_id), ao2_cleanup);</span><br><span>                if (!snapshot) {</span><br><span>                     ast_ari_response_error(response, 404, "Not found",</span><br><span>                                 "Bridge not found");</span><br><span>@@ -856,7 +856,7 @@</span><br><span>         struct ast_ari_bridges_get_args *args,</span><br><span>       struct ast_ari_response *response)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+    RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_get_snapshot_by_uniqueid(args->bridge_id), ao2_cleanup);</span><br><span>      if (!snapshot) {</span><br><span>             ast_ari_response_error(</span><br><span>                      response, 404, "Not Found",</span><br><span>@@ -885,23 +885,13 @@</span><br><span>        struct ast_ari_bridges_list_args *args,</span><br><span>      struct ast_ari_response *response)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-      RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);</span><br><span>        RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);</span><br><span>     struct ao2_iterator i;</span><br><span style="color: hsl(0, 100%, 40%);">-  void *obj;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_bridge *bridge;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  cache = ast_bridge_cache();</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!cache) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_ari_response_error(</span><br><span style="color: hsl(0, 100%, 40%);">-                 response, 500, "Internal Server Error",</span><br><span style="color: hsl(0, 100%, 40%);">-                       "Message bus not initialized");</span><br><span style="color: hsl(0, 100%, 40%);">-               return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       ao2_ref(cache, +1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!snapshots) {</span><br><span style="color: hsl(120, 100%, 40%);">+     bridges = ast_bridges();</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!bridges) {</span><br><span>              ast_ari_response_alloc_failed(response);</span><br><span>             return;</span><br><span>      }</span><br><span>@@ -912,12 +902,14 @@</span><br><span>            return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   i = ao2_iterator_init(snapshots, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    while ((obj = ao2_iterator_next(&i))) {</span><br><span style="color: hsl(0, 100%, 40%);">-             RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">-               struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+      i = ao2_iterator_init(bridges, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    while ((bridge = ao2_iterator_next(&i))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct ast_bridge_snapshot *snapshot = ast_bridge_get_snapshot(bridge);</span><br><span style="color: hsl(120, 100%, 40%);">+               /* ast_bridge_snapshot_to_json will return NULL if snapshot is NULL */</span><br><span>               struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         ao2_ref(bridge, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_cleanup(snapshot);</span><br><span>               if (!json_bridge || ast_json_array_append(json, json_bridge)) {</span><br><span>                      ao2_iterator_destroy(&i);</span><br><span>                        ast_ari_response_alloc_failed(response);</span><br><span>diff --git a/res/res_stasis.c b/res/res_stasis.c</span><br><span>index 43833e1..86723a1 100644</span><br><span>--- a/res/res_stasis.c</span><br><span>+++ b/res/res_stasis.c</span><br><span>@@ -1974,7 +1974,7 @@</span><br><span>                        have_channel = 1;</span><br><span>            } else if (ast_begins_with(uri, "bridge:")) {</span><br><span>                      type = STASIS_UMOS_BRIDGE;</span><br><span style="color: hsl(0, 100%, 40%);">-                      snapshot = ast_bridge_snapshot_get_latest(uri + 7);</span><br><span style="color: hsl(120, 100%, 40%);">+                   snapshot = ast_bridge_get_snapshot_by_uniqueid(uri + 7);</span><br><span>             } else if (ast_begins_with(uri, "endpoint:")) {</span><br><span>                    type = STASIS_UMOS_ENDPOINT;</span><br><span>                         snapshot = ast_endpoint_latest_snapshot(uri + 9, NULL);</span><br><span>diff --git a/res/stasis/app.c b/res/stasis/app.c</span><br><span>index 78f5765..eb49243 100644</span><br><span>--- a/res/stasis/app.c</span><br><span>+++ b/res/stasis/app.c</span><br><span>@@ -172,16 +172,9 @@</span><br><span>  }</span><br><span> </span><br><span>        forwards->forward_type = FORWARD_BRIDGE;</span><br><span style="color: hsl(0, 100%, 40%);">-     if (bridge) {</span><br><span style="color: hsl(0, 100%, 40%);">-           forwards->topic_forward = stasis_forward_all(ast_bridge_topic(bridge),</span><br><span style="color: hsl(0, 100%, 40%);">-                       app->topic);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       forwards->topic_cached_forward = stasis_forward_all(</span><br><span style="color: hsl(0, 100%, 40%);">-         bridge ? ast_bridge_topic_cached(bridge) : ast_bridge_topic_all_cached(),</span><br><span style="color: hsl(0, 100%, 40%);">-               app->topic);</span><br><span style="color: hsl(120, 100%, 40%);">+       forwards->topic_forward = stasis_forward_all(ast_bridge_topic(bridge), app->topic);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if ((!forwards->topic_forward && bridge) || !forwards->topic_cached_forward) {</span><br><span style="color: hsl(0, 100%, 40%);">-            /* Half-subscribed is a bad thing */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!forwards->topic_forward && bridge) {</span><br><span>                 forwards_unsubscribe(forwards);</span><br><span>              ao2_ref(forwards, -1);</span><br><span>               return NULL;</span><br><span>@@ -666,33 +659,23 @@</span><br><span> {</span><br><span>    struct ast_json *json = NULL;</span><br><span>        struct stasis_app *app = data;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct stasis_cache_update *update;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct ast_bridge_snapshot *new_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_bridge_snapshot *old_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_bridge_snapshot_update *update;</span><br><span>   const struct timeval *tv;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_assert(stasis_message_type(message) == stasis_cache_update_type());</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>      update = stasis_message_data(message);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      ast_assert(update->type == ast_bridge_snapshot_type());</span><br><span style="color: hsl(120, 100%, 40%);">+    tv = stasis_message_timestamp(message);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     new_snapshot = stasis_message_data(update->new_snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">-    old_snapshot = stasis_message_data(update->old_snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">-    tv = update->new_snapshot ?</span><br><span style="color: hsl(0, 100%, 40%);">-          stasis_message_timestamp(update->new_snapshot) :</span><br><span style="color: hsl(0, 100%, 40%);">-             stasis_message_timestamp(message);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!new_snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">-            json = simple_bridge_event("BridgeDestroyed", old_snapshot, tv);</span><br><span style="color: hsl(0, 100%, 40%);">-      } else if (!old_snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">-             json = simple_bridge_event("BridgeCreated", new_snapshot, tv);</span><br><span style="color: hsl(0, 100%, 40%);">-        } else if (new_snapshot && old_snapshot</span><br><span style="color: hsl(0, 100%, 40%);">-         && strcmp(new_snapshot->video_source_id, old_snapshot->video_source_id)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                json = simple_bridge_event("BridgeVideoSourceChanged", new_snapshot, tv);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (json && !ast_strlen_zero(old_snapshot->video_source_id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!update->new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+               json = simple_bridge_event("BridgeDestroyed", update->old_snapshot, tv);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!update->old_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+                json = simple_bridge_event("BridgeCreated", update->new_snapshot, tv);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (update->new_snapshot && update->old_snapshot</span><br><span style="color: hsl(120, 100%, 40%);">+         && strcmp(update->new_snapshot->video_source_id, update->old_snapshot->video_source_id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                json = simple_bridge_event("BridgeVideoSourceChanged", update->new_snapshot, tv);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (json && !ast_strlen_zero(update->old_snapshot->video_source_id)) {</span><br><span>                         ast_json_object_set(json, "old_video_source_id",</span><br><span style="color: hsl(0, 100%, 40%);">-                              ast_json_string_create(old_snapshot->video_source_id));</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_json_string_create(update->old_snapshot->video_source_id));</span><br><span>                }</span><br><span>    }</span><br><span> </span><br><span>@@ -701,8 +684,8 @@</span><br><span>          ast_json_unref(json);</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!new_snapshot && old_snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">-            unsubscribe(app, "bridge", old_snapshot->uniqueid, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!update->new_snapshot && update->old_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unsubscribe(app, "bridge", update->old_snapshot->uniqueid, 1);</span><br><span>       }</span><br><span> }</span><br><span> </span><br><span>@@ -961,7 +944,7 @@</span><br><span>             return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   res |= stasis_message_router_add_cache_update(app->router,</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= stasis_message_router_add(app->router,</span><br><span>             ast_bridge_snapshot_type(), sub_bridge_update_handler, app);</span><br><span> </span><br><span>     res |= stasis_message_router_add(app->router,</span><br><span>diff --git a/tests/test_cel.c b/tests/test_cel.c</span><br><span>index 6c8bd61..902362d 100644</span><br><span>--- a/tests/test_cel.c</span><br><span>+++ b/tests/test_cel.c</span><br><span>@@ -351,7 +351,7 @@</span><br><span> static struct ast_str *test_cel_generate_peer_str_snapshot(struct ast_channel_snapshot *chan, struct ast_bridge *bridge)</span><br><span> {</span><br><span>         RAII_VAR(struct ast_bridge_snapshot *, snapshot,</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_bridge_snapshot_get_latest(bridge->uniqueid),</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_bridge_get_snapshot(bridge),</span><br><span>             ao2_cleanup);</span><br><span> </span><br><span>    if (!snapshot) {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/10227">change 10227</a>. To unsubscribe, or for help writing mail filters, 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/10227"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I7049b80efa88676ce5c4666f818fa18ad1985369 </div>
<div style="display:none"> Gerrit-Change-Number: 10227 </div>
<div style="display:none"> Gerrit-PatchSet: 7 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Corey Farrell <git@cfware.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 (1000185) </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </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>