<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/10478">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Joshua Colp: Looks good to me, approved
Jenkins2: Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">stasis: Use an implementation specific channel snapshot cache.<br><br>Channels no longer use the Stasis cache for channel snapshots. Instead<br>they are stored in a hash table in stasis_channels which reduces the<br>number of Stasis messages created and allows better storage.<br><br>As a result the following APIs are no longer available since the stasis<br>cache is no longer used:<br>ast_channel_topic_cached()<br>ast_channel_topic_all_cached()<br><br>The ast_channel_cache_all() and ast_channel_cache_by_name() functions<br>now return an ao2_container of ast_channel_snapshots rather than<br>a container of stasis_messages therefore you can't (and don't need<br>to) call stasis_cache functions on it.<br><br>The ast_channel_topic_all() function now returns a normal topic not<br>a cached one so you can't use stasis cache functions on it either.<br><br>The ast_channel_snapshot_type() stasis message now has the<br>ast_channel_snapshot_update structure as it's data. It contains the<br>last snapshot and the new one.<br><br>ast_channel_snapshot_get_latest() still returns the latest snapshot.<br><br>The latest snapshot is now stored on the channel itself to eliminate<br>cache hits when Stasis messages that have the snapshot as a payload<br>are created.<br><br>ASTERISK-28102<br><br>Change-Id: I9334febff60a82d7c39703e49059fa3a68825786<br>---<br>M CHANGES<br>M UPGRADE.txt<br>M apps/app_agent_pool.c<br>M apps/confbridge/confbridge_manager.c<br>M channels/chan_pjsip.c<br>M channels/pjsip/cli_commands.c<br>M include/asterisk/channel.h<br>M include/asterisk/stasis_channels.h<br>M main/aoc.c<br>M main/app.c<br>M main/bridge.c<br>M main/cdr.c<br>M main/cel.c<br>M main/channel.c<br>M main/channel_internal_api.c<br>M main/cli.c<br>M main/endpoints.c<br>M main/manager.c<br>M main/manager_bridges.c<br>M main/manager_channels.c<br>M main/stasis_channels.c<br>M res/ari/resource_channels.c<br>M res/res_agi.c<br>M res/res_chan_stats.c<br>M res/stasis/app.c<br>M res/stasis/control.c<br>M tests/test_cel.c<br>M tests/test_stasis_endpoints.c<br>28 files changed, 456 insertions(+), 551 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 2c98062..111a030 100644</span><br><span>--- a/CHANGES</span><br><span>+++ b/CHANGES</span><br><span>@@ -19,6 +19,22 @@</span><br><span> https://wiki.asterisk.org/wiki/x/tAHOAQ</span><br><span> https://wiki.asterisk.org/wiki/x/hYCLAQ</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+Channels</span><br><span style="color: hsl(120, 100%, 40%);">+------------------</span><br><span style="color: hsl(120, 100%, 40%);">+ * The core no longer uses the stasis cache for channels snapshots.</span><br><span style="color: hsl(120, 100%, 40%);">+ The following APIs are no longer available:</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_all_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+ The ast_channel_cache_all() and ast_channel_cache_by_name() functions</span><br><span style="color: hsl(120, 100%, 40%);">+ now returns an ao2_container of ast_channel_snapshots rather than a</span><br><span style="color: hsl(120, 100%, 40%);">+ container of stasis_messages therefore you can't call stasis_cache</span><br><span style="color: hsl(120, 100%, 40%);">+ functions on it.</span><br><span style="color: hsl(120, 100%, 40%);">+ The ast_channel_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 either.</span><br><span style="color: hsl(120, 100%, 40%);">+ The ast_channel_snapshot_type() stasis message now has the</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_update structure as it's data.</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_get_latest() still returns the latest snapshot.</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 3cf8e27..c299d83 100644</span><br><span>--- a/UPGRADE.txt</span><br><span>+++ b/UPGRADE.txt</span><br><span>@@ -43,3 +43,18 @@</span><br><span> </span><br><span> res_xmpp:</span><br><span> - 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%);">+Channels:</span><br><span style="color: hsl(120, 100%, 40%);">+ - The core no longer uses the stasis cache for channels snapshots.</span><br><span style="color: hsl(120, 100%, 40%);">+ The following APIs are no longer available:</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_all_cached()</span><br><span style="color: hsl(120, 100%, 40%);">+ The ast_channel_cache_all() and ast_channel_cache_by_name() functions</span><br><span style="color: hsl(120, 100%, 40%);">+ now returns an ao2_container of ast_channel_snapshots rather than a</span><br><span style="color: hsl(120, 100%, 40%);">+ container of stasis_messages therefore you can't call stasis_cache</span><br><span style="color: hsl(120, 100%, 40%);">+ functions on it.</span><br><span style="color: hsl(120, 100%, 40%);">+ The ast_channel_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 either.</span><br><span style="color: hsl(120, 100%, 40%);">+ The ast_channel_snapshot_type() stasis message now has the</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_update structure as it's data.</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_get_latest() still returns the latest snapshot.</span><br><span>diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c</span><br><span>index 805c403..5bd6a4d 100644</span><br><span>--- a/apps/app_agent_pool.c</span><br><span>+++ b/apps/app_agent_pool.c</span><br><span>@@ -1448,7 +1448,7 @@</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_cached_blob(chan, ast_channel_agent_login_type(), blob);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_blob(chan, ast_channel_agent_login_type(), blob);</span><br><span> }</span><br><span> </span><br><span> static void send_agent_logoff(struct ast_channel *chan, const char *agent, long logintime)</span><br><span>@@ -1464,7 +1464,7 @@</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_cached_blob(chan, ast_channel_agent_logoff_type(), blob);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_blob(chan, ast_channel_agent_logoff_type(), blob);</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c</span><br><span>index e88bbc2..2d85033 100644</span><br><span>--- a/apps/confbridge/confbridge_manager.c</span><br><span>+++ b/apps/confbridge/confbridge_manager.c</span><br><span>@@ -783,7 +783,7 @@</span><br><span> }</span><br><span> </span><br><span> channel_state_router = stasis_message_router_create(</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_topic_all_cached());</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_all());</span><br><span> </span><br><span> if (!channel_state_router) {</span><br><span> manager_confbridge_shutdown();</span><br><span>diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c</span><br><span>index 9edd989..d0a74cd 100644</span><br><span>--- a/channels/chan_pjsip.c</span><br><span>+++ b/channels/chan_pjsip.c</span><br><span>@@ -1135,7 +1135,6 @@</span><br><span> RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", data), ao2_cleanup);</span><br><span> enum ast_device_state state = AST_DEVICE_UNKNOWN;</span><br><span> RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);</span><br><span> struct ast_devstate_aggregate aggregate;</span><br><span> int num, inuse = 0;</span><br><span> </span><br><span>@@ -1156,27 +1155,20 @@</span><br><span> state = AST_DEVICE_NOT_INUSE;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!endpoint_snapshot->num_channels || !(cache = ast_channel_cache())) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endpoint_snapshot->num_channels) {</span><br><span> return state;</span><br><span> }</span><br><span> </span><br><span> ast_devstate_aggregate_init(&aggregate);</span><br><span> </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> for (num = 0; num < endpoint_snapshot->num_channels; num++) {</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);</span><br><span> struct ast_channel_snapshot *snapshot;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- msg = stasis_cache_get(cache, ast_channel_snapshot_type(),</span><br><span style="color: hsl(0, 100%, 40%);">- endpoint_snapshot->channel_ids[num]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!snapshot) {</span><br><span> continue;</span><br><span> }</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%);">-</span><br><span> if (chan_pjsip_get_hold(snapshot->uniqueid)) {</span><br><span> ast_devstate_aggregate_add(&aggregate, AST_DEVICE_ONHOLD);</span><br><span> } else {</span><br><span>@@ -1187,6 +1179,8 @@</span><br><span> (snapshot->state == AST_STATE_BUSY)) {</span><br><span> inuse++;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> }</span><br><span> </span><br><span> if (endpoint->devicestate_busy_at && (inuse == endpoint->devicestate_busy_at)) {</span><br><span>diff --git a/channels/pjsip/cli_commands.c b/channels/pjsip/cli_commands.c</span><br><span>index 33d0e02..9a8dc29 100644</span><br><span>--- a/channels/pjsip/cli_commands.c</span><br><span>+++ b/channels/pjsip/cli_commands.c</span><br><span>@@ -169,9 +169,8 @@</span><br><span> </span><br><span> static int cli_message_to_snapshot(void *obj, void *arg, int flags)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *message = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *snapshot = obj;</span><br><span> struct ao2_container *snapshots = arg;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot = stasis_message_data(message);</span><br><span> </span><br><span> if (!strcmp(snapshot->type, "PJSIP")) {</span><br><span> ao2_link(snapshots, snapshot);</span><br><span>@@ -198,8 +197,7 @@</span><br><span> {</span><br><span> struct ao2_container *child_container;</span><br><span> regex_t regexbuf;</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct ao2_container *, parent_container,</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()), ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ao2_container *, parent_container, ast_channel_cache_by_name(), ao2_cleanup);</span><br><span> </span><br><span> if (!parent_container) {</span><br><span> return NULL;</span><br><span>diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h</span><br><span>index 3f22cdd..9627ae2 100644</span><br><span>--- a/include/asterisk/channel.h</span><br><span>+++ b/include/asterisk/channel.h</span><br><span>@@ -148,6 +148,15 @@</span><br><span> #define AST_MAX_PUBLIC_UNIQUEID 149</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * The number of buckets to store channels or channel information</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef LOW_MEMORY</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_NUM_CHANNEL_BUCKETS 61</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_NUM_CHANNEL_BUCKETS 1567</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * Maximum size of an internal Asterisk channel unique ID.</span><br><span> *</span><br><span> * \details</span><br><span>@@ -2650,6 +2659,17 @@</span><br><span> void ast_channel_internal_swap_topics(struct ast_channel *a, struct ast_channel *b);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Swap snapshots beteween two channels</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param a First channel</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param b Second channel</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return void</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is used in masquerade to exchange snapshots</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_channel_internal_swap_snapshots(struct ast_channel *a, struct ast_channel *b);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Set uniqueid and linkedid string value only (not time)</span><br><span> * \param chan The channel to set the uniqueid to</span><br><span> * \param uniqueid The uniqueid to set</span><br><span>@@ -4236,6 +4256,8 @@</span><br><span> void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value);</span><br><span> enum ast_channel_state ast_channel_state(const struct ast_channel *chan);</span><br><span> ast_callid ast_channel_callid(const struct ast_channel *chan);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_channel_snapshot *ast_channel_snapshot(const struct ast_channel *chan);</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot);</span><br><span> </span><br><span> /*!</span><br><span> * \pre chan is locked</span><br><span>@@ -4562,21 +4584,6 @@</span><br><span> struct stasis_topic *ast_channel_topic(struct ast_channel *chan);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \since 12</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief A topic which publishes the events for a particular channel.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \ref ast_channel_snapshot messages are replaced with \ref stasis_cache_update</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * If the given \a chan is \c NULL, ast_channel_topic_all_cached() is returned.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \param chan Channel, or \c NULL.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval Topic for channel's events.</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval ast_channel_topic_all() if \a chan 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_channel_topic_cached(struct ast_channel *chan);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span> * \brief Get the bridge associated with a channel</span><br><span> * \since 12.0.0</span><br><span> *</span><br><span>diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h</span><br><span>index 4843617..2aeff6f 100644</span><br><span>--- a/include/asterisk/stasis_channels.h</span><br><span>+++ b/include/asterisk/stasis_channels.h</span><br><span>@@ -76,6 +76,23 @@</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Structure representing a change of snapshot of channel state.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * While not enforced programmatically, this object is shared across multiple</span><br><span style="color: hsl(120, 100%, 40%);">+ * threads, and should be treated as an immutable object.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This structure will not have a transition of an old snapshot with no</span><br><span style="color: hsl(120, 100%, 40%);">+ * new snapshot to indicate that a channel has gone away. A new snapshot will</span><br><span style="color: hsl(120, 100%, 40%);">+ * always exist and a channel going away can be determined by checking for the</span><br><span style="color: hsl(120, 100%, 40%);">+ * AST_FLAG_DEAD flag on the new snapshot.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_channel_snapshot_update {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *old_snapshot; /*!< The old channel snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *new_snapshot; /*!< The new channel 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%);">+/*!</span><br><span> * \since 12</span><br><span> * \brief Blob of data associated with a channel.</span><br><span> *</span><br><span>@@ -94,7 +111,7 @@</span><br><span> */</span><br><span> struct ast_multi_channel_blob;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_cp_all *ast_channel_cache_all(void);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ao2_container *ast_channel_cache_all(void);</span><br><span> </span><br><span> /*!</span><br><span> * \since 12</span><br><span>@@ -105,34 +122,17 @@</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_channel_snapshot messages from</span><br><span style="color: hsl(0, 100%, 40%);">- * ast_channel_events_all(void).</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval Topic for all channel events.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_topic *ast_channel_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 Primary channel cache, indexed by Uniqueid.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval Cache of \ref ast_channel_snapshot.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_cache *ast_channel_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 Secondary channel cache, indexed by name.</span><br><span> *</span><br><span> * \retval Cache of \ref ast_channel_snapshot.</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_cache *ast_channel_cache_by_name(void);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ao2_container *ast_channel_cache_by_name(void);</span><br><span> </span><br><span> /*!</span><br><span> * \since 12</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Message type for \ref ast_channel_snapshot.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Message type for \ref ast_channel_snapshot_update.</span><br><span> *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval Message type for \ref ast_channel_snapshot.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval Message type for \ref ast_channel_snapshot_update.</span><br><span> */</span><br><span> struct stasis_message_type *ast_channel_snapshot_type(void);</span><br><span> </span><br><span>@@ -176,6 +176,18 @@</span><br><span> struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Send the final channel snapshot for a channel, thus removing it from cache</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \pre chan is locked</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan The channel to send the final channel snapshot for</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This will also remove the cached snapshot from the channel itself</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_channel_publish_final_snapshot(struct ast_channel *chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \since 12</span><br><span> * \brief Creates a \ref ast_channel_blob message.</span><br><span> *</span><br><span>@@ -303,6 +315,8 @@</span><br><span> * \param type Type of stasis message.</span><br><span> * \param blob The blob being published. (NULL if no blob)</span><br><span> *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This will use the current snapshot on the channel and will not generate a new one.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span> * \return Nothing</span><br><span> */</span><br><span> void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type,</span><br><span>@@ -557,17 +571,6 @@</span><br><span> const char *dialstatus,</span><br><span> const char *forward);</span><br><span> </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 Publish in the \ref ast_channel_topic a \ref ast_channel_snapshot</span><br><span style="color: hsl(0, 100%, 40%);">- * message indicating a change in channel state</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \pre chan is locked</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \param chan The channel whose state has changed</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-void ast_publish_channel_state(struct ast_channel *chan);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! @} */</span><br><span> </span><br><span> /*!</span><br><span>diff --git a/main/aoc.c b/main/aoc.c</span><br><span>index 253c745..b8cf301 100644</span><br><span>--- a/main/aoc.c</span><br><span>+++ b/main/aoc.c</span><br><span>@@ -1849,7 +1849,9 @@</span><br><span> }</span><br><span> </span><br><span> if (chan) {</span><br><span style="color: hsl(0, 100%, 40%);">- aoc_event->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ aoc_event->snapshot = ao2_bump(ast_channel_snapshot(chan));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span> if (!aoc_event->snapshot) {</span><br><span> ao2_ref(aoc_event, -1);</span><br><span> return;</span><br><span>diff --git a/main/app.c b/main/app.c</span><br><span>index 953b77d..ec74490 100644</span><br><span>--- a/main/app.c</span><br><span>+++ b/main/app.c</span><br><span>@@ -3244,15 +3244,7 @@</span><br><span> mwi_state->old_msgs = old_msgs;</span><br><span> </span><br><span> if (!ast_strlen_zero(channel_id)) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *chan_message;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- chan_message = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),</span><br><span style="color: hsl(0, 100%, 40%);">- channel_id);</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_message) {</span><br><span style="color: hsl(0, 100%, 40%);">- mwi_state->snapshot = stasis_message_data(chan_message);</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(mwi_state->snapshot, +1);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_cleanup(chan_message);</span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_state->snapshot = ast_channel_snapshot_get_latest(channel_id);</span><br><span> }</span><br><span> </span><br><span> if (eid) {</span><br><span>diff --git a/main/bridge.c b/main/bridge.c</span><br><span>index d6e7a51..024c6ab 100644</span><br><span>--- a/main/bridge.c</span><br><span>+++ b/main/bridge.c</span><br><span>@@ -5150,16 +5150,15 @@</span><br><span> {</span><br><span> const char *uniqueid = obj;</span><br><span> struct ast_cli_args *a = arg;</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);</span><br><span> struct ast_channel_snapshot *snapshot;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(), uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ snapshot = ast_channel_snapshot_get_latest(uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!snapshot) {</span><br><span> return 0;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- snapshot = stasis_message_data(msg);</span><br><span> </span><br><span> ast_cli(a->fd, "Channel: %s\n", snapshot->name);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span>diff --git a/main/cdr.c b/main/cdr.c</span><br><span>index 1c47e24..e321c22 100644</span><br><span>--- a/main/cdr.c</span><br><span>+++ b/main/cdr.c</span><br><span>@@ -186,14 +186,6 @@</span><br><span> </configInfo></span><br><span> ***/</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* The prime here should be similar in size to the channel container. */</span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef LOW_MEMORY</span><br><span style="color: hsl(0, 100%, 40%);">-#define NUM_CDR_BUCKETS 61</span><br><span style="color: hsl(0, 100%, 40%);">-#else</span><br><span style="color: hsl(0, 100%, 40%);">-#define NUM_CDR_BUCKETS 769</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> #define DEFAULT_ENABLED "1"</span><br><span> #define DEFAULT_BATCHMODE "0"</span><br><span> #define DEFAULT_UNANSWERED "0"</span><br><span>@@ -2056,9 +2048,9 @@</span><br><span> </span><br><span> /*!</span><br><span> * \internal</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Filter a channel cache update</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Filter a channel snapshot update</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-static int filter_channel_cache_message(struct ast_channel_snapshot *old_snapshot,</span><br><span style="color: hsl(120, 100%, 40%);">+static int filter_channel_snapshot_message(struct ast_channel_snapshot *old_snapshot,</span><br><span> struct ast_channel_snapshot *new_snapshot)</span><br><span> {</span><br><span> int ret = 0;</span><br><span>@@ -2256,52 +2248,38 @@</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Handler for Stasis-Core channel cache update messages</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Handler for channel snapshot update messages</span><br><span> * \param data Passed on</span><br><span> * \param sub The stasis subscription for this message callback</span><br><span> * \param topic The topic this message was published for</span><br><span> * \param message The message</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-static void handle_channel_cache_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)</span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_channel_snapshot_update_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)</span><br><span> {</span><br><span> struct cdr_object *cdr;</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_cache_update *update = stasis_message_data(message);</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *old_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *new_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update = stasis_message_data(message);</span><br><span> struct cdr_object *it_cdr;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_assert(update != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_assert(ast_channel_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 style="color: hsl(0, 100%, 40%);">- if (filter_channel_cache_message(old_snapshot, new_snapshot)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (filter_channel_snapshot_message(update->old_snapshot, update->new_snapshot)) {</span><br><span> return;</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%);">- cdr = cdr_object_alloc(new_snapshot);</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%);">+ cdr = cdr_object_alloc(update->new_snapshot);</span><br><span> if (!cdr) {</span><br><span> return;</span><br><span> }</span><br><span> cdr->is_root = 1;</span><br><span> ao2_link(active_cdrs_master, cdr);</span><br><span> } else {</span><br><span style="color: hsl(0, 100%, 40%);">- const char *uniqueid;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid;</span><br><span style="color: hsl(0, 100%, 40%);">- cdr = ao2_find(active_cdrs_master, uniqueid, OBJ_SEARCH_KEY);</span><br><span style="color: hsl(120, 100%, 40%);">+ cdr = ao2_find(active_cdrs_master, update->new_snapshot->uniqueid, OBJ_SEARCH_KEY);</span><br><span> }</span><br><span> </span><br><span> /* Handle Party A */</span><br><span> if (!cdr) {</span><br><span style="color: hsl(0, 100%, 40%);">- const char *name;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- name = new_snapshot ? new_snapshot->name : old_snapshot->name;</span><br><span style="color: hsl(0, 100%, 40%);">- ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->name);</span><br><span> ast_assert(0);</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span> int all_reject = 1;</span><br><span> </span><br><span> ao2_lock(cdr);</span><br><span>@@ -2309,21 +2287,23 @@</span><br><span> if (!it_cdr->fn_table->process_party_a) {</span><br><span> continue;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- all_reject &= it_cdr->fn_table->process_party_a(it_cdr, new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ all_reject &= it_cdr->fn_table->process_party_a(it_cdr, update->new_snapshot);</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (all_reject && check_new_cdr_needed(update->old_snapshot, update->new_snapshot)) {</span><br><span> /* We're not hung up and we have a new snapshot - we need a new CDR */</span><br><span> struct cdr_object *new_cdr;</span><br><span> </span><br><span> new_cdr = cdr_object_create_and_append(cdr);</span><br><span> if (new_cdr) {</span><br><span style="color: hsl(0, 100%, 40%);">- new_cdr->fn_table->process_party_a(new_cdr, new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ new_cdr->fn_table->process_party_a(new_cdr, update->new_snapshot);</span><br><span> }</span><br><span> }</span><br><span> ao2_unlock(cdr);</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</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_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {</span><br><span> ao2_lock(cdr);</span><br><span style="color: hsl(0, 100%, 40%);">- CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name);</span><br><span style="color: hsl(120, 100%, 40%);">+ CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->name);</span><br><span> for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {</span><br><span> cdr_object_finalize(it_cdr);</span><br><span> }</span><br><span>@@ -2335,12 +2315,14 @@</span><br><span> }</span><br><span> </span><br><span> /* Handle Party B */</span><br><span style="color: hsl(0, 100%, 40%);">- if (new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (update->new_snapshot) {</span><br><span> ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,</span><br><span style="color: hsl(0, 100%, 40%);">- cdr_object_update_party_b, (char *) new_snapshot->name, new_snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ cdr_object_update_party_b, (char *) update->new_snapshot->name, 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%);">+ if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {</span><br><span> ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,</span><br><span style="color: hsl(0, 100%, 40%);">- cdr_object_finalize_party_b, (char *) old_snapshot->name, old_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ cdr_object_finalize_party_b, (char *) update->new_snapshot->name, update->new_snapshot);</span><br><span> }</span><br><span> </span><br><span> ao2_cleanup(cdr);</span><br><span>@@ -4302,7 +4284,7 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- channel_subscription = stasis_forward_all(ast_channel_topic_all_cached(), cdr_topic);</span><br><span style="color: hsl(120, 100%, 40%);">+ channel_subscription = stasis_forward_all(ast_channel_topic_all(), cdr_topic);</span><br><span> if (!channel_subscription) {</span><br><span> return -1;</span><br><span> }</span><br><span>@@ -4522,7 +4504,7 @@</span><br><span> return AST_MODULE_LOAD_FAILURE;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- stasis_message_router_add_cache_update(stasis_router, ast_channel_snapshot_type(), handle_channel_cache_message, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ stasis_message_router_add(stasis_router, ast_channel_snapshot_type(), handle_channel_snapshot_update_message, NULL);</span><br><span> stasis_message_router_add(stasis_router, ast_channel_dial_type(), handle_dial_message, NULL);</span><br><span> stasis_message_router_add(stasis_router, ast_channel_entered_bridge_type(), handle_bridge_enter_message, NULL);</span><br><span> stasis_message_router_add(stasis_router, ast_channel_left_bridge_type(), handle_bridge_leave_message, NULL);</span><br><span>@@ -4530,14 +4512,14 @@</span><br><span> stasis_message_router_add(stasis_router, cdr_sync_message_type(), handle_cdr_sync_message, NULL);</span><br><span> </span><br><span> active_cdrs_master = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,</span><br><span style="color: hsl(0, 100%, 40%);">- NUM_CDR_BUCKETS, cdr_master_hash_fn, NULL, cdr_master_cmp_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_NUM_CHANNEL_BUCKETS, cdr_master_hash_fn, NULL, cdr_master_cmp_fn);</span><br><span> if (!active_cdrs_master) {</span><br><span> return AST_MODULE_LOAD_FAILURE;</span><br><span> }</span><br><span> ao2_container_register("cdrs_master", active_cdrs_master, cdr_master_print_fn);</span><br><span> </span><br><span> active_cdrs_all = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,</span><br><span style="color: hsl(0, 100%, 40%);">- NUM_CDR_BUCKETS, cdr_all_hash_fn, NULL, cdr_all_cmp_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_NUM_CHANNEL_BUCKETS, cdr_all_hash_fn, NULL, cdr_all_cmp_fn);</span><br><span> if (!active_cdrs_all) {</span><br><span> return AST_MODULE_LOAD_FAILURE;</span><br><span> }</span><br><span>diff --git a/main/cel.c b/main/cel.c</span><br><span>index feb3bee..97e35ad 100644</span><br><span>--- a/main/cel.c</span><br><span>+++ b/main/cel.c</span><br><span>@@ -888,14 +888,6 @@</span><br><span> {</span><br><span> int is_hungup, was_hungup;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!new_snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">- cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_cel_track_event(AST_CEL_LINKEDID_END)) {</span><br><span style="color: hsl(0, 100%, 40%);">- check_retire_linkedid(old_snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">- }</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%);">-</span><br><span> if (!old_snapshot) {</span><br><span> cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);</span><br><span> return;</span><br><span>@@ -915,6 +907,11 @@</span><br><span> cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);</span><br><span> ast_json_unref(extra);</span><br><span> ao2_cleanup(dialstatus);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_cel_track_event(AST_CEL_LINKEDID_END)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ check_retire_linkedid(new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span>@@ -928,7 +925,7 @@</span><br><span> struct ast_channel_snapshot *old_snapshot,</span><br><span> struct ast_channel_snapshot *new_snapshot)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!old_snapshot || !new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!old_snapshot) {</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span>@@ -946,8 +943,7 @@</span><br><span> struct ast_channel_snapshot *old_snapshot,</span><br><span> struct ast_channel_snapshot *new_snapshot)</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%);">- && !strcmp(old_snapshot->appl, new_snapshot->appl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (old_snapshot && !strcmp(old_snapshot->appl, new_snapshot->appl)) {</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span>@@ -957,7 +953,7 @@</span><br><span> }</span><br><span> </span><br><span> /* new snapshot has an application, start it */</span><br><span style="color: hsl(0, 100%, 40%);">- if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(new_snapshot->appl)) {</span><br><span> cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);</span><br><span> }</span><br><span> }</span><br><span>@@ -984,22 +980,15 @@</span><br><span> static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,</span><br><span> struct stasis_message *message)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_cache_update *update = stasis_message_data(message);</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_channel_snapshot_type() == update->type) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *old_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *new_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- size_t i;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update = stasis_message_data(message);</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t i;</span><br><span> </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(120, 100%, 40%);">+ if (cel_filter_channel_snapshot(update->old_snapshot) || cel_filter_channel_snapshot(update->new_snapshot)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (cel_filter_channel_snapshot(old_snapshot) || cel_filter_channel_snapshot(new_snapshot)) {</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {</span><br><span style="color: hsl(0, 100%, 40%);">- cel_channel_monitors[i](old_snapshot, new_snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ cel_channel_monitors[i](update->old_snapshot, update->new_snapshot);</span><br><span> }</span><br><span> }</span><br><span> </span><br><span>@@ -1453,7 +1442,7 @@</span><br><span> }</span><br><span> </span><br><span> cel_channel_forwarder = stasis_forward_all(</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_topic_all_cached(),</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_all(),</span><br><span> cel_aggregation_topic);</span><br><span> if (!cel_channel_forwarder) {</span><br><span> return -1;</span><br><span>@@ -1498,7 +1487,7 @@</span><br><span> 6 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL);</span><br><span> </span><br><span> ret |= stasis_message_router_add(cel_state_router,</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_cache_update_type(),</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_type(),</span><br><span> cel_snapshot_update_cb,</span><br><span> NULL);</span><br><span> </span><br><span>diff --git a/main/channel.c b/main/channel.c</span><br><span>index 6c6e9f7..3d8e244 100644</span><br><span>--- a/main/channel.c</span><br><span>+++ b/main/channel.c</span><br><span>@@ -116,12 +116,6 @@</span><br><span> /*! \brief the list of registered channel types */</span><br><span> static AST_RWLIST_HEAD_STATIC(backends, chanlist);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#ifdef LOW_MEMORY</span><br><span style="color: hsl(0, 100%, 40%);">-#define NUM_CHANNEL_BUCKETS 61</span><br><span style="color: hsl(0, 100%, 40%);">-#else</span><br><span style="color: hsl(0, 100%, 40%);">-#define NUM_CHANNEL_BUCKETS 1567</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! \brief All active channels on the system */</span><br><span> static struct ao2_container *channels;</span><br><span> </span><br><span>@@ -635,38 +629,6 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_message *create_channel_snapshot_message(struct ast_channel *channel)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct ast_channel_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_channel_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_channel_lock(channel);</span><br><span style="color: hsl(0, 100%, 40%);">- snapshot = ast_channel_snapshot_create(channel);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_unlock(channel);</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_channel_snapshot_type(), snapshot);</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%);">-static void publish_cache_clear(struct ast_channel *chan)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);</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_channel_snapshot_message(chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!clear_msg) {</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- message = stasis_cache_clear_create(clear_msg);</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_publish(ast_channel_topic(chan), message);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /*! \brief Gives the string form of a given channel state.</span><br><span> *</span><br><span> * \note This function is not reentrant.</span><br><span>@@ -1236,7 +1198,9 @@</span><br><span> "musicclass", musicclass);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_cached_blob(chan, ast_channel_hold_type(), blob);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_blob(chan, ast_channel_hold_type(), blob);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span> </span><br><span> res = ast_queue_frame(chan, &f);</span><br><span> </span><br><span>@@ -1250,7 +1214,9 @@</span><br><span> struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD };</span><br><span> int res;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_cached_blob(chan, ast_channel_unhold_type(), NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_blob(chan, ast_channel_unhold_type(), NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span> </span><br><span> res = ast_queue_frame(chan, &f);</span><br><span> </span><br><span>@@ -2230,9 +2196,8 @@</span><br><span> ast_assert(!ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE));</span><br><span> </span><br><span> ast_channel_lock(chan);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_snapshot(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_final_snapshot(chan);</span><br><span> ast_channel_unlock(chan);</span><br><span style="color: hsl(0, 100%, 40%);">- publish_cache_clear(chan);</span><br><span> }</span><br><span> </span><br><span> ast_channel_lock(chan);</span><br><span>@@ -3344,7 +3309,7 @@</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_cached_blob(chan, ast_channel_dtmf_begin_type(), blob);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_blob(chan, ast_channel_dtmf_begin_type(), blob);</span><br><span> }</span><br><span> </span><br><span> static void send_dtmf_end_event(struct ast_channel *chan,</span><br><span>@@ -3361,7 +3326,7 @@</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_cached_blob(chan, ast_channel_dtmf_end_type(), blob);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_blob(chan, ast_channel_dtmf_end_type(), blob);</span><br><span> }</span><br><span> </span><br><span> static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f)</span><br><span>@@ -6819,6 +6784,9 @@</span><br><span> /* Make sure the Stasis topic on the channel is updated appropriately */</span><br><span> ast_channel_internal_swap_topics(clonechan, original);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* The old snapshots need to follow the channels so the snapshot update is correct */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_internal_swap_snapshots(clonechan, original);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Swap channel names. This uses ast_channel_name_set directly, so we</span><br><span> * don't get any spurious rename events.</span><br><span> */</span><br><span>@@ -7246,7 +7214,7 @@</span><br><span> </span><br><span> ast_channel_state_set(chan, state);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ast_publish_channel_state(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_snapshot(chan);</span><br><span> </span><br><span> /* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver</span><br><span> * for this channel is using the callback method for device state. If we pass in an actual state here</span><br><span>@@ -7856,7 +7824,7 @@</span><br><span> </span><br><span> int ast_channels_init(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- channels = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NUM_CHANNEL_BUCKETS,</span><br><span style="color: hsl(120, 100%, 40%);">+ channels = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, AST_NUM_CHANNEL_BUCKETS,</span><br><span> ast_channel_hash_cb, NULL, ast_channel_cmp_cb);</span><br><span> if (!channels) {</span><br><span> return -1;</span><br><span>diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c</span><br><span>index a963a7d..436ba23 100644</span><br><span>--- a/main/channel_internal_api.c</span><br><span>+++ b/main/channel_internal_api.c</span><br><span>@@ -42,7 +42,6 @@</span><br><span> #include "asterisk/channel_internal.h"</span><br><span> #include "asterisk/endpoints.h"</span><br><span> #include "asterisk/indications.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/stasis_cache_pattern.h"</span><br><span> #include "asterisk/stasis_channels.h"</span><br><span> #include "asterisk/stasis_endpoints.h"</span><br><span> #include "asterisk/stringfields.h"</span><br><span>@@ -215,12 +214,13 @@</span><br><span> char dtmf_digit_to_emulate; /*!< Digit being emulated */</span><br><span> char sending_dtmf_digit; /*!< Digit this channel is currently sending out. (zero if not sending) */</span><br><span> struct timeval sending_dtmf_tv; /*!< The time this channel started sending the current digit. (Invalid if sending_dtmf_digit is zero.) */</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_cp_single *topics; /*!< Topic for all channel's events */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_topic *topic; /*!< Topic for trhis channel */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_forward *channel_forward; /*!< Subscription for event forwarding to all channel topic */</span><br><span> struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */</span><br><span> struct ast_stream_topology *stream_topology; /*!< Stream topology */</span><br><span> void *stream_topology_change_source; /*!< Source that initiated a stream topology change */</span><br><span> struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *snapshot; /*!< The current up to date snapshot of the channel */</span><br><span> };</span><br><span> </span><br><span> /*! \brief The monotonically increasing integer counter for channel uniqueids */</span><br><span>@@ -1381,11 +1381,25 @@</span><br><span> </span><br><span> void ast_channel_internal_swap_topics(struct ast_channel *a, struct ast_channel *b)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_cp_single *temp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_topic *topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_forward *forward;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- temp = a->topics;</span><br><span style="color: hsl(0, 100%, 40%);">- a->topics = b->topics;</span><br><span style="color: hsl(0, 100%, 40%);">- b->topics = temp;</span><br><span style="color: hsl(120, 100%, 40%);">+ topic = a->topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ a->topic = b->topic;</span><br><span style="color: hsl(120, 100%, 40%);">+ b->topic = topic;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ forward = a->channel_forward;</span><br><span style="color: hsl(120, 100%, 40%);">+ a->channel_forward = b->channel_forward;</span><br><span style="color: hsl(120, 100%, 40%);">+ b->channel_forward = forward;</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_channel_internal_swap_snapshots(struct ast_channel *a, struct ast_channel *b)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ snapshot = a->snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ a->snapshot = b->snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ b->snapshot = snapshot;</span><br><span> }</span><br><span> </span><br><span> void ast_channel_internal_set_fake_ids(struct ast_channel *chan, const char *uniqueid, const char *linkedid)</span><br><span>@@ -1404,11 +1418,11 @@</span><br><span> </span><br><span> ast_string_field_free_memory(chan);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ chan->channel_forward = stasis_forward_cancel(chan->channel_forward);</span><br><span> chan->endpoint_forward = stasis_forward_cancel(chan->endpoint_forward);</span><br><span style="color: hsl(0, 100%, 40%);">- chan->endpoint_cache_forward = stasis_forward_cancel(chan->endpoint_cache_forward);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- stasis_cp_single_unsubscribe(chan->topics);</span><br><span style="color: hsl(0, 100%, 40%);">- chan->topics = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(chan->topic);</span><br><span style="color: hsl(120, 100%, 40%);">+ chan->topic = NULL;</span><br><span> </span><br><span> ast_channel_internal_set_stream_topology(chan, NULL);</span><br><span> </span><br><span>@@ -1431,16 +1445,7 @@</span><br><span> return ast_channel_topic_all();</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- return stasis_cp_single_topic(chan->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_channel_topic_cached(struct ast_channel *chan)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- if (!chan) {</span><br><span style="color: hsl(0, 100%, 40%);">- return ast_channel_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(chan->topics);</span><br><span style="color: hsl(120, 100%, 40%);">+ return chan->topic;</span><br><span> }</span><br><span> </span><br><span> int ast_channel_forward_endpoint(struct ast_channel *chan,</span><br><span>@@ -1456,28 +1461,28 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- chan->endpoint_cache_forward = stasis_forward_all(ast_channel_topic_cached(chan),</span><br><span style="color: hsl(0, 100%, 40%);">- ast_endpoint_topic(endpoint));</span><br><span style="color: hsl(0, 100%, 40%);">- if (!chan->endpoint_cache_forward) {</span><br><span style="color: hsl(0, 100%, 40%);">- chan->endpoint_forward = stasis_forward_cancel(chan->endpoint_forward);</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> return 0;</span><br><span> }</span><br><span> </span><br><span> int ast_channel_internal_setup_topics(struct ast_channel *chan)</span><br><span> {</span><br><span> const char *topic_name = chan->uniqueid.unique_id;</span><br><span style="color: hsl(0, 100%, 40%);">- ast_assert(chan->topics == NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_assert(chan->topic == NULL);</span><br><span> </span><br><span> if (ast_strlen_zero(topic_name)) {</span><br><span> topic_name = "<dummy-channel>";</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- chan->topics = stasis_cp_single_create(</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_cache_all(), topic_name);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!chan->topics) {</span><br><span style="color: hsl(120, 100%, 40%);">+ chan->topic = stasis_topic_create(topic_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!chan->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%);">+ chan->channel_forward = stasis_forward_all(ast_channel_topic(chan),</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_all());</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!chan->channel_forward) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(chan->topic, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ chan->topic = NULL;</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span>@@ -1568,3 +1573,14 @@</span><br><span> {</span><br><span> return (chan->tech && chan->tech->read_stream && chan->tech->write_stream);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_channel_snapshot *ast_channel_snapshot(const struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return chan->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%);">+void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(chan->snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ chan->snapshot = ao2_bump(snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/main/cli.c b/main/cli.c</span><br><span>index cf51d0d..5484e47 100644</span><br><span>--- a/main/cli.c</span><br><span>+++ b/main/cli.c</span><br><span>@@ -956,7 +956,7 @@</span><br><span> </span><br><span> struct ao2_container *channels;</span><br><span> struct ao2_iterator it_chans;</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *cs;</span><br><span> int numchans = 0, concise = 0, verbose = 0, count = 0;</span><br><span> </span><br><span> switch (cmd) {</span><br><span>@@ -989,11 +989,7 @@</span><br><span> } else if (a->argc != e->args - 1)</span><br><span> return CLI_SHOWUSAGE;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!(channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()))) {</span><br><span style="color: hsl(0, 100%, 40%);">- ast_cli(a->fd, "Failed to retrieve cached channels\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(120, 100%, 40%);">+ channels = ast_channel_cache_by_name();</span><br><span> </span><br><span> if (!count) {</span><br><span> if (!concise && !verbose)</span><br><span>@@ -1004,8 +1000,7 @@</span><br><span> }</span><br><span> </span><br><span> it_chans = ao2_iterator_init(channels, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *cs = stasis_message_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {</span><br><span> char durbuf[16] = "-";</span><br><span> </span><br><span> if (!count) {</span><br><span>@@ -1679,29 +1674,25 @@</span><br><span> struct ao2_container *cached_channels;</span><br><span> char *ret = NULL;</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_channel_snapshot *snapshot;</span><br><span> </span><br><span> if (pos != rpos) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!(cached_channels = stasis_cache_dump(ast_channel_cache(), ast_channel_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(120, 100%, 40%);">+ cached_channels = ast_channel_cache_all();</span><br><span> </span><br><span> iter = ao2_iterator_init(cached_channels, 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_channel_snapshot *snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ for (; (snapshot = ao2_iterator_next(&iter)); ao2_ref(snapshot, -1)) {</span><br><span> if (!strncasecmp(word, snapshot->name, wordlen) && (++which > state)) {</span><br><span> if (state != -1) {</span><br><span> ret = ast_strdup(snapshot->name);</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(msg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> break;</span><br><span> }</span><br><span> </span><br><span> if (ast_cli_completion_add(ast_strdup(snapshot->name))) {</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(msg, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> break;</span><br><span> }</span><br><span> }</span><br><span>diff --git a/main/endpoints.c b/main/endpoints.c</span><br><span>index 030e26c..f3e3372 100644</span><br><span>--- a/main/endpoints.c</span><br><span>+++ b/main/endpoints.c</span><br><span>@@ -179,25 +179,23 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Handler for channel snapshot cache clears */</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Handler for channel snapshot update */</span><br><span> static void endpoint_cache_clear(void *data,</span><br><span> struct stasis_subscription *sub,</span><br><span> struct stasis_message *message)</span><br><span> {</span><br><span> struct ast_endpoint *endpoint = data;</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *clear_msg = stasis_message_data(message);</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *clear_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update = stasis_message_data(message);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (stasis_message_type(clear_msg) != ast_channel_snapshot_type()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Only when the channel is dead do we remove it */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- clear_snapshot = stasis_message_data(clear_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> ast_assert(endpoint != NULL);</span><br><span> </span><br><span> ao2_lock(endpoint);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_str_container_remove(endpoint->channel_ids, clear_snapshot->uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_container_remove(endpoint->channel_ids, update->new_snapshot->uniqueid);</span><br><span> ao2_unlock(endpoint);</span><br><span> endpoint_publish_snapshot(endpoint);</span><br><span> }</span><br><span>@@ -271,7 +269,7 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> r |= stasis_message_router_add(endpoint->router,</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_cache_clear_type(), endpoint_cache_clear,</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_type(), endpoint_cache_clear,</span><br><span> endpoint);</span><br><span> r |= stasis_message_router_add(endpoint->router,</span><br><span> stasis_subscription_change_type(), endpoint_subscription_change,</span><br><span>diff --git a/main/manager.c b/main/manager.c</span><br><span>index 0469a73..76a827c 100644</span><br><span>--- a/main/manager.c</span><br><span>+++ b/main/manager.c</span><br><span>@@ -6250,7 +6250,7 @@</span><br><span> int numchans = 0;</span><br><span> struct ao2_container *channels;</span><br><span> struct ao2_iterator it_chans;</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *cs;</span><br><span> </span><br><span> if (!ast_strlen_zero(actionid)) {</span><br><span> snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);</span><br><span>@@ -6258,17 +6258,12 @@</span><br><span> idText[0] = '\0';</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type());</span><br><span style="color: hsl(0, 100%, 40%);">- if (!channels) {</span><br><span style="color: hsl(0, 100%, 40%);">- astman_send_error(s, m, "Could not get cached channels");</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(120, 100%, 40%);">+ channels = ast_channel_cache_by_name();</span><br><span> </span><br><span> astman_send_listack(s, m, "Channels will follow", "start");</span><br><span> </span><br><span> it_chans = ao2_iterator_init(channels, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *cs = stasis_message_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {</span><br><span> struct ast_str *built = ast_manager_build_channel_state_string_prefix(cs, "");</span><br><span> char durbuf[16] = "";</span><br><span> </span><br><span>diff --git a/main/manager_bridges.c b/main/manager_bridges.c</span><br><span>index b7059f4..1b57049 100644</span><br><span>--- a/main/manager_bridges.c</span><br><span>+++ b/main/manager_bridges.c</span><br><span>@@ -528,17 +528,14 @@</span><br><span> char *uniqueid = obj;</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 stasis_message *, msg, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);</span><br><span> RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- msg = stasis_cache_get(ast_channel_cache(),</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_snapshot_type(), uniqueid);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ snapshot = ast_channel_snapshot_get_latest(uniqueid);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!snapshot) {</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> if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {</span><br><span> return 0;</span><br><span> }</span><br><span>diff --git a/main/manager_channels.c b/main/manager_channels.c</span><br><span>index ac09d42..887f77e 100644</span><br><span>--- a/main/manager_channels.c</span><br><span>+++ b/main/manager_channels.c</span><br><span>@@ -576,11 +576,6 @@</span><br><span> {</span><br><span> int is_hungup, was_hungup;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!new_snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Ignore cache clearing events; we'll see the hangup first */</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> /* The Newchannel, Newstate and Hangup events are closely related, in</span><br><span> * in that they are mutually exclusive, basically different flavors</span><br><span> * of a new channel state event.</span><br><span>@@ -616,11 +611,6 @@</span><br><span> struct ast_channel_snapshot *old_snapshot,</span><br><span> struct ast_channel_snapshot *new_snapshot)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- /* No Newexten event on cache clear */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!new_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> /* Empty application is not valid for a Newexten event */</span><br><span> if (ast_strlen_zero(new_snapshot->appl)) {</span><br><span> return NULL;</span><br><span>@@ -654,8 +644,8 @@</span><br><span> struct ast_manager_event_blob *res;</span><br><span> char *callerid;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* No NewCallerid event on cache clear or first event */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!old_snapshot || !new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* No NewCallerid event on first channel snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!old_snapshot) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -682,8 +672,8 @@</span><br><span> struct ast_channel_snapshot *old_snapshot,</span><br><span> struct ast_channel_snapshot *new_snapshot)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- /* No NewConnectedLine event on cache clear or first event */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!old_snapshot || !new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* No NewConnectedLine event on first channel snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!old_snapshot) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -699,7 +689,7 @@</span><br><span> struct ast_channel_snapshot *old_snapshot,</span><br><span> struct ast_channel_snapshot *new_snapshot)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!old_snapshot || !new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!old_snapshot) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -724,21 +714,14 @@</span><br><span> struct stasis_message *message)</span><br><span> {</span><br><span> RAII_VAR(struct ast_str *, channel_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_channel_snapshot *old_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *new_snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_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_channel_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(channel_monitors); ++i) {</span><br><span> RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">- ev = channel_monitors[i](old_snapshot, new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ ev = channel_monitors[i](update->old_snapshot, update->new_snapshot);</span><br><span> </span><br><span> if (!ev) {</span><br><span> continue;</span><br><span>@@ -747,7 +730,7 @@</span><br><span> /* If we haven't already, build the channel event string */</span><br><span> if (!channel_event_string) {</span><br><span> channel_event_string =</span><br><span style="color: hsl(0, 100%, 40%);">- ast_manager_build_channel_state_string(new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_manager_build_channel_state_string(update->new_snapshot);</span><br><span> if (!channel_event_string) {</span><br><span> return;</span><br><span> }</span><br><span>@@ -1260,7 +1243,7 @@</span><br><span> if (!message_router) {</span><br><span> return -1;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- channel_topic = ast_channel_topic_all_cached();</span><br><span style="color: hsl(120, 100%, 40%);">+ channel_topic = ast_channel_topic_all();</span><br><span> if (!channel_topic) {</span><br><span> return -1;</span><br><span> }</span><br><span>@@ -1272,7 +1255,7 @@</span><br><span> </span><br><span> ast_register_cleanup(manager_channels_shutdown);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ret |= stasis_message_router_add_cache_update(message_router,</span><br><span style="color: hsl(120, 100%, 40%);">+ ret |= stasis_message_router_add(message_router,</span><br><span> ast_channel_snapshot_type(), channel_snapshot_update, NULL);</span><br><span> </span><br><span> ret |= stasis_message_router_add(message_router,</span><br><span>diff --git a/main/stasis_channels.c b/main/stasis_channels.c</span><br><span>index 0da8005..ec8d70c 100644</span><br><span>--- a/main/stasis_channels.c</span><br><span>+++ b/main/stasis_channels.c</span><br><span>@@ -36,7 +36,6 @@</span><br><span> #include "asterisk/bridge.h"</span><br><span> #include "asterisk/translate.h"</span><br><span> #include "asterisk/stasis.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/stasis_cache_pattern.h"</span><br><span> #include "asterisk/stasis_channels.h"</span><br><span> #include "asterisk/dial.h"</span><br><span> #include "asterisk/linkedlists.h"</span><br><span>@@ -117,53 +116,23 @@</span><br><span> </span><br><span> #define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_cp_all *channel_cache_all;</span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_cache *channel_cache_by_name;</span><br><span style="color: hsl(0, 100%, 40%);">-static struct stasis_caching_topic *channel_by_name_topic;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stasis_topic *channel_topic_all;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ao2_container *channel_cache;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ao2_container *channel_cache_by_name;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_cp_all *ast_channel_cache_all(void)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ao2_container *ast_channel_cache_all(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return channel_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_cache *ast_channel_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(channel_cache_all);</span><br><span style="color: hsl(120, 100%, 40%);">+ return ao2_bump(channel_cache);</span><br><span> }</span><br><span> </span><br><span> struct stasis_topic *ast_channel_topic_all(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return stasis_cp_all_topic(channel_cache_all);</span><br><span style="color: hsl(120, 100%, 40%);">+ return channel_topic_all;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct stasis_topic *ast_channel_topic_all_cached(void)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ao2_container *ast_channel_cache_by_name(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- return stasis_cp_all_topic_cached(channel_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_cache *ast_channel_cache_by_name(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- return channel_cache_by_name;</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%);">-static const char *channel_snapshot_get_id(struct stasis_message *message)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_channel_snapshot_type() != stasis_message_type(message)) {</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%);">- snapshot = stasis_message_data(message);</span><br><span style="color: hsl(0, 100%, 40%);">- return snapshot->uniqueid;</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%);">-static const char *channel_snapshot_get_name(struct stasis_message *message)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_channel_snapshot_type() != stasis_message_type(message)) {</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%);">- snapshot = stasis_message_data(message);</span><br><span style="color: hsl(0, 100%, 40%);">- return snapshot->name;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ao2_bump(channel_cache_by_name);</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>@@ -219,6 +188,59 @@</span><br><span> return CMP_MATCH;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Hash function (using uniqueid) for \ref ast_channel_snapshot objects</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_channel_snapshot *object = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *key;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (flags & OBJ_SEARCH_MASK) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case OBJ_SEARCH_KEY:</span><br><span style="color: hsl(120, 100%, 40%);">+ key = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case OBJ_SEARCH_OBJECT:</span><br><span style="color: hsl(120, 100%, 40%);">+ key = object->uniqueid;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_assert(0);</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%);">+ return ast_str_case_hash(key);</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%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Comparison function (using uniqueid) for \ref ast_channel_snapshot objects</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_channel_snapshot *object_left = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_channel_snapshot *object_right = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *right_key = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+ int cmp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (flags & OBJ_SEARCH_MASK) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case OBJ_SEARCH_OBJECT:</span><br><span style="color: hsl(120, 100%, 40%);">+ right_key = object_right->uniqueid;</span><br><span style="color: hsl(120, 100%, 40%);">+ case OBJ_SEARCH_KEY:</span><br><span style="color: hsl(120, 100%, 40%);">+ cmp = strcasecmp(object_left->uniqueid, right_key);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case OBJ_SEARCH_PARTIAL_KEY:</span><br><span style="color: hsl(120, 100%, 40%);">+ cmp = strncasecmp(object_left->uniqueid, right_key, strlen(right_key));</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ cmp = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cmp) {</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%);">+ return CMP_MATCH;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void channel_snapshot_dtor(void *obj)</span><br><span> {</span><br><span> struct ast_channel_snapshot *snapshot = obj;</span><br><span>@@ -309,6 +331,34 @@</span><br><span> return snapshot;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void channel_snapshot_update_dtor(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</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_channel_snapshot_update *channel_snapshot_update_create(struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_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), channel_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 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->old_snapshot = ao2_bump(ast_channel_snapshot(chan));</span><br><span style="color: hsl(120, 100%, 40%);">+ update->new_snapshot = ast_channel_snapshot_create(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!update->new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(update, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</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 update;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)</span><br><span> {</span><br><span> if (chan) {</span><br><span>@@ -521,7 +571,7 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- snapshot = chan ? ast_channel_snapshot_create(chan) : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ snapshot = chan ? ao2_bump(ast_channel_snapshot(chan)) : NULL;</span><br><span> msg = create_channel_blob_message(snapshot, type, blob);</span><br><span> ao2_cleanup(snapshot);</span><br><span> return msg;</span><br><span>@@ -628,38 +678,48 @@</span><br><span> </span><br><span> struct ast_channel_snapshot *ast_channel_snapshot_get_latest(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(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-</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_channel_cache(), ast_channel_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(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%);">- 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(0, 100%, 40%);">- return snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ao2_find(channel_cache, uniqueid, OBJ_SEARCH_KEY);</span><br><span> }</span><br><span> </span><br><span> struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *message;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> ast_assert(!ast_strlen_zero(name));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- message = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(),</span><br><span style="color: hsl(0, 100%, 40%);">- name);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!message) {</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ao2_find(channel_cache_by_name, name, OBJ_SEARCH_KEY);</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_channel_publish_final_snapshot(struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stasis_message *message;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_channel_snapshot_type()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- snapshot = ao2_bump(stasis_message_data(message));</span><br><span style="color: hsl(120, 100%, 40%);">+ update = channel_snapshot_update_create(chan);</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%);">+ message = stasis_message_create(ast_channel_snapshot_type(), update);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* In the success path message holds a reference to update so it will be valid</span><br><span style="color: hsl(120, 100%, 40%);">+ * for the lifetime of this function until the end.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(update, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!message) {</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%);">+ ao2_unlink(channel_cache, update->old_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlink(channel_cache_by_name, update->old_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_set(chan, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ stasis_publish(ast_channel_topic(chan), message);</span><br><span> ao2_ref(message, -1);</span><br><span style="color: hsl(0, 100%, 40%);">- return snapshot;</span><br><span> }</span><br><span> </span><br><span> static void channel_role_snapshot_dtor(void *obj)</span><br><span>@@ -764,7 +824,7 @@</span><br><span> </span><br><span> void ast_channel_publish_snapshot(struct ast_channel *chan)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update;</span><br><span> struct stasis_message *message;</span><br><span> </span><br><span> if (!ast_channel_snapshot_type()) {</span><br><span>@@ -775,17 +835,40 @@</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- snapshot = ast_channel_snapshot_create(chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ update = channel_snapshot_update_create(chan);</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%);">- message = stasis_message_create(ast_channel_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%);">+ message = stasis_message_create(ast_channel_snapshot_type(), update);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* In the success path message holds a reference to update so it will be valid</span><br><span style="color: hsl(120, 100%, 40%);">+ * for the lifetime of this function until the end.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(update, -1);</span><br><span> if (!message) {</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* We lock these ourselves so that the update is atomic and there isn't time where a</span><br><span style="color: hsl(120, 100%, 40%);">+ * snapshot is not in the cache.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_wrlock(channel_cache);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (update->old_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlink_flags(channel_cache, update->old_snapshot, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_link_flags(channel_cache, update->new_snapshot, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(channel_cache);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The same applies here. */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_wrlock(channel_cache_by_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (update->old_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlink_flags(channel_cache_by_name, update->old_snapshot, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_link_flags(channel_cache_by_name, update->new_snapshot, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(channel_cache_by_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_snapshot_set(chan, update->new_snapshot);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ast_assert(ast_channel_topic(chan) != NULL);</span><br><span> stasis_publish(ast_channel_topic(chan), message);</span><br><span> ao2_ref(message, -1);</span><br><span>@@ -841,13 +924,8 @@</span><br><span> ast_channel_publish_snapshot(chan);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (chan) {</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_cached_blob(chan, ast_channel_varset_type(), blob);</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- /* This function is NULL safe for global variables */</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_publish_blob(NULL, ast_channel_varset_type(), blob);</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%);">+ /* This function is NULL safe for global variables */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_publish_blob(chan, ast_channel_varset_type(), blob);</span><br><span> ast_json_unref(blob);</span><br><span> }</span><br><span> </span><br><span>@@ -931,36 +1009,6 @@</span><br><span> return ev;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void ast_publish_channel_state(struct ast_channel *chan)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *message;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!ast_channel_snapshot_type()) {</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ast_assert(chan != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!chan) {</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- snapshot = ast_channel_snapshot_create(chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!snapshot) {</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- message = stasis_message_create(ast_channel_snapshot_type(), snapshot);</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(snapshot, -1);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!message) {</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ast_assert(ast_channel_topic(chan) != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_publish(ast_channel_topic(chan), message);</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(message, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct ast_json *ast_channel_snapshot_to_json(</span><br><span> const struct ast_channel_snapshot *snapshot,</span><br><span> const struct stasis_message_sanitizer *sanitize)</span><br><span>@@ -1332,12 +1380,12 @@</span><br><span> </span><br><span> static void stasis_channels_cleanup(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_caching_unsubscribe_and_join(channel_by_name_topic);</span><br><span style="color: hsl(0, 100%, 40%);">- channel_by_name_topic = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(channel_topic_all);</span><br><span style="color: hsl(120, 100%, 40%);">+ channel_topic_all = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(channel_cache);</span><br><span style="color: hsl(120, 100%, 40%);">+ channel_cache = NULL;</span><br><span> ao2_cleanup(channel_cache_by_name);</span><br><span> channel_cache_by_name = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_cleanup(channel_cache_all);</span><br><span style="color: hsl(0, 100%, 40%);">- channel_cache_all = NULL;</span><br><span> </span><br><span> STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type);</span><br><span> STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type);</span><br><span>@@ -1367,29 +1415,28 @@</span><br><span> </span><br><span> ast_register_cleanup(stasis_channels_cleanup);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- channel_cache_all = stasis_cp_all_create("ast_channel_topic_all",</span><br><span style="color: hsl(0, 100%, 40%);">- channel_snapshot_get_id);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!channel_cache_all) {</span><br><span style="color: hsl(120, 100%, 40%);">+ channel_topic_all = stasis_topic_create("ast_channel_topic_all");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!channel_topic_all) {</span><br><span> return -1;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_login_type);</span><br><span style="color: hsl(0, 100%, 40%);">- res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_logoff_type);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- channel_cache_by_name = stasis_cache_create(channel_snapshot_get_name);</span><br><span style="color: hsl(120, 100%, 40%);">+ channel_cache = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0, AST_NUM_CHANNEL_BUCKETS, channel_snapshot_uniqueid_hash_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ NULL, channel_snapshot_uniqueid_cmp_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!channel_cache) {</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%);">+ channel_cache_by_name = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0, AST_NUM_CHANNEL_BUCKETS, channel_snapshot_hash_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ NULL, channel_snapshot_cmp_cb);</span><br><span> if (!channel_cache_by_name) {</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* This should be initialized before the caching topic */</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_login_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_logoff_type);</span><br><span> res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- channel_by_name_topic = stasis_caching_topic_create(</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_cp_all_topic(channel_cache_all),</span><br><span style="color: hsl(0, 100%, 40%);">- channel_cache_by_name);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!channel_by_name_topic) {</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> res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type);</span><br><span> res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type);</span><br><span> res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);</span><br><span>diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c</span><br><span>index bca32f1..f96192b 100644</span><br><span>--- a/res/ari/resource_channels.c</span><br><span>+++ b/res/ari/resource_channels.c</span><br><span>@@ -833,32 +833,19 @@</span><br><span> struct ast_ari_channels_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 stasis_message *, msg, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_cache *cache;</span><br><span> struct ast_channel_snapshot *snapshot;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- cache = ast_channel_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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- msg = stasis_cache_get(cache, ast_channel_snapshot_type(),</span><br><span style="color: hsl(0, 100%, 40%);">- args->channel_id);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ snapshot = ast_channel_snapshot_get_latest(args->channel_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!snapshot) {</span><br><span> ast_ari_response_error(</span><br><span> response, 404, "Not Found",</span><br><span> "Channel not found");</span><br><span> return;</span><br><span> }</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%);">- ast_assert(snapshot != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> ast_ari_response_ok(response,</span><br><span> ast_channel_snapshot_to_json(snapshot, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> }</span><br><span> </span><br><span> void ast_ari_channels_hangup(struct ast_variable *headers,</span><br><span>@@ -903,27 +890,13 @@</span><br><span> struct ast_ari_channels_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> RAII_VAR(struct ao2_container *, snapshots, 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> void *obj;</span><br><span> struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- cache = ast_channel_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_channel_snapshot_type());</span><br><span style="color: hsl(0, 100%, 40%);">- if (!snapshots) {</span><br><span style="color: hsl(0, 100%, 40%);">- ast_ari_response_alloc_failed(response);</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(120, 100%, 40%);">+ snapshots = ast_channel_cache_all();</span><br><span> </span><br><span> json = ast_json_array_create();</span><br><span> if (!json) {</span><br><span>@@ -933,12 +906,12 @@</span><br><span> </span><br><span> i = ao2_iterator_init(snapshots, 0);</span><br><span> 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_channel_snapshot *snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *snapshot = obj;</span><br><span> int r;</span><br><span> </span><br><span> if (sanitize && sanitize->channel_snapshot</span><br><span> && sanitize->channel_snapshot(snapshot)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> continue;</span><br><span> }</span><br><span> </span><br><span>@@ -947,8 +920,10 @@</span><br><span> if (r != 0) {</span><br><span> ast_ari_response_alloc_failed(response);</span><br><span> ao2_iterator_destroy(&i);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> return;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> }</span><br><span> ao2_iterator_destroy(&i);</span><br><span> </span><br><span>diff --git a/res/res_agi.c b/res/res_agi.c</span><br><span>index 0931c1a..e322d7f 100644</span><br><span>--- a/res/res_agi.c</span><br><span>+++ b/res/res_agi.c</span><br><span>@@ -3182,13 +3182,13 @@</span><br><span> ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));</span><br><span> return RESULT_SUCCESS;</span><br><span> } else if (argc == 3) {</span><br><span style="color: hsl(0, 100%, 40%);">- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot *snapshot;</span><br><span> </span><br><span> /* one argument: look for info on the specified channel */</span><br><span style="color: hsl(0, 100%, 40%);">- if ((msg = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(), argv[2]))) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ snapshot = ast_channel_snapshot_get_latest_by_name(argv[2]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (snapshot) {</span><br><span> ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(snapshot, -1);</span><br><span> return RESULT_SUCCESS;</span><br><span> }</span><br><span> /* if we get this far no channel name matched the argument given */</span><br><span>diff --git a/res/res_chan_stats.c b/res/res_chan_stats.c</span><br><span>index dbc79f0..bed95a0 100644</span><br><span>--- a/res/res_chan_stats.c</span><br><span>+++ b/res/res_chan_stats.c</span><br><span>@@ -78,7 +78,7 @@</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Router callback for \ref stasis_cache_update messages.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Router callback for \ref ast_channel_snapshot_update messages.</span><br><span> * \param data Data pointer given when added to router.</span><br><span> * \param sub This subscription.</span><br><span> * \param topic The topic the message was posted to. This is not necessarily the</span><br><span>@@ -92,34 +92,25 @@</span><br><span> /* Since this came from a message router, we know the type of the</span><br><span> * message. We can cast the data without checking its type.</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_cache_update *update = stasis_message_data(message);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update = stasis_message_data(message);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* We're only interested in channel snapshots, so check the type</span><br><span style="color: hsl(0, 100%, 40%);">- * of the underlying message.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_channel_snapshot_type() != update->type) {</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* There are three types of cache updates.</span><br><span style="color: hsl(0, 100%, 40%);">- * !old && new -> Initial cache entry</span><br><span style="color: hsl(0, 100%, 40%);">- * old && new -> Updated cache entry</span><br><span style="color: hsl(0, 100%, 40%);">- * old && !new -> Cache entry removed.</span><br><span style="color: hsl(120, 100%, 40%);">+ /* There are three types of channel snapshot updates.</span><br><span style="color: hsl(120, 100%, 40%);">+ * !old && new -> Initial channel creation</span><br><span style="color: hsl(120, 100%, 40%);">+ * old && new -> Updated channel snapshot</span><br><span style="color: hsl(120, 100%, 40%);">+ * old && dead -> Final channel snapshot</span><br><span> */</span><br><span> </span><br><span> if (!update->old_snapshot && update->new_snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Initial cache entry; count a channel creation */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Initial channel snapshot; count a channel creation */</span><br><span> ast_statsd_log_string("channels.count", AST_STATSD_GAUGE, "+1", 1.0);</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (update->old_snapshot && !update->new_snapshot) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Cache entry removed. Compute the age of the channel and post</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (update->old_snapshot && ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Channel is gone. Compute the age of the channel and post</span><br><span> * that, as well as decrementing the channel count.</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *last;</span><br><span> int64_t age;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- last = stasis_message_data(update->old_snapshot);</span><br><span> age = ast_tvdiff_ms(*stasis_message_timestamp(message),</span><br><span style="color: hsl(0, 100%, 40%);">- last->creationtime);</span><br><span style="color: hsl(120, 100%, 40%);">+ update->new_snapshot->creationtime);</span><br><span> ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age);</span><br><span> </span><br><span> /* And decrement the channel count */</span><br><span>@@ -161,11 +152,11 @@</span><br><span> {</span><br><span> /* You can create a message router to route messages by type */</span><br><span> router = stasis_message_router_create(</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_topic_all_cached());</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_topic_all());</span><br><span> if (!router) {</span><br><span> return AST_MODULE_LOAD_DECLINE;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_message_router_add(router, stasis_cache_update_type(),</span><br><span style="color: hsl(120, 100%, 40%);">+ stasis_message_router_add(router, ast_channel_snapshot_type(),</span><br><span> updates, NULL);</span><br><span> stasis_message_router_set_default(router, default_route, NULL);</span><br><span> </span><br><span>diff --git a/res/stasis/app.c b/res/stasis/app.c</span><br><span>index 18ac7d6..b4f3bc6 100644</span><br><span>--- a/res/stasis/app.c</span><br><span>+++ b/res/stasis/app.c</span><br><span>@@ -144,17 +144,11 @@</span><br><span> }</span><br><span> </span><br><span> forwards->forward_type = FORWARD_CHANNEL;</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan) {</span><br><span style="color: hsl(0, 100%, 40%);">- forwards->topic_forward = stasis_forward_all(ast_channel_topic(chan),</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%);">- chan ? ast_channel_topic_cached(chan) : ast_channel_topic_all_cached(),</span><br><span style="color: hsl(120, 100%, 40%);">+ forwards->topic_forward = stasis_forward_all(</span><br><span style="color: hsl(120, 100%, 40%);">+ chan ? ast_channel_topic(chan) : ast_channel_topic_all(),</span><br><span> app->topic);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if ((!forwards->topic_forward && chan) || !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(0, 100%, 40%);">- forwards_unsubscribe(forwards);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!forwards->topic_forward) {</span><br><span> ao2_ref(forwards, -1);</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -420,7 +414,7 @@</span><br><span> </span><br><span> if (!old_snapshot) {</span><br><span> return channel_created_event(snapshot, tv);</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (!new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD)) {</span><br><span> return channel_destroyed_event(snapshot, tv);</span><br><span> } else if (old_snapshot->state != new_snapshot->state) {</span><br><span> return channel_state_change_event(snapshot, tv);</span><br><span>@@ -436,8 +430,8 @@</span><br><span> {</span><br><span> struct ast_json *json_channel;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* No Newexten event on cache clear or first event */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!old_snapshot || !new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* No Newexten event on first channel snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!old_snapshot) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -470,8 +464,8 @@</span><br><span> {</span><br><span> struct ast_json *json_channel;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* No NewCallerid event on cache clear or first event */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!old_snapshot || !new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* No NewCallerid event on first channel snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!old_snapshot) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -500,8 +494,8 @@</span><br><span> {</span><br><span> struct ast_json *json_channel;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* No ChannelConnectedLine event on cache clear or first event */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!old_snapshot || !new_snapshot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* No ChannelConnectedLine event on first channel snapshot */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!old_snapshot) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span>@@ -532,39 +526,22 @@</span><br><span> struct stasis_message *message)</span><br><span> {</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_channel_snapshot *new_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *old_snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">- const struct timeval *tv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel_snapshot_update *update = stasis_message_data(message);</span><br><span> int i;</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 style="color: hsl(0, 100%, 40%);">- update = stasis_message_data(message);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ast_assert(update->type == ast_channel_snapshot_type());</span><br><span style="color: hsl(0, 100%, 40%);">-</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Pull timestamp from the new snapshot, or from the update message</span><br><span style="color: hsl(0, 100%, 40%);">- * when there isn't one. */</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> for (i = 0; i < ARRAY_LEN(channel_monitors); ++i) {</span><br><span> struct ast_json *msg;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- msg = channel_monitors[i](old_snapshot, new_snapshot, tv);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = channel_monitors[i](update->old_snapshot, update->new_snapshot,</span><br><span style="color: hsl(120, 100%, 40%);">+ stasis_message_timestamp(message));</span><br><span> if (msg) {</span><br><span> app_send(app, msg);</span><br><span> ast_json_unref(msg);</span><br><span> }</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, "channel", old_snapshot->uniqueid, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ unsubscribe(app, "channel", update->new_snapshot->uniqueid, 1);</span><br><span> }</span><br><span> }</span><br><span> </span><br><span>@@ -987,7 +964,7 @@</span><br><span> res |= stasis_message_router_add_cache_update(app->router,</span><br><span> ast_bridge_snapshot_type(), sub_bridge_update_handler, app);</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_channel_snapshot_type(), sub_channel_update_handler, app);</span><br><span> </span><br><span> res |= stasis_message_router_add_cache_update(app->router,</span><br><span>diff --git a/res/stasis/control.c b/res/stasis/control.c</span><br><span>index e4d007c..5b3b048 100644</span><br><span>--- a/res/stasis/control.c</span><br><span>+++ b/res/stasis/control.c</span><br><span>@@ -773,22 +773,7 @@</span><br><span> struct ast_channel_snapshot *stasis_app_control_get_snapshot(</span><br><span> const struct stasis_app_control *control)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- struct stasis_message *msg;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_channel_snapshot *snapshot;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),</span><br><span style="color: hsl(0, 100%, 40%);">- stasis_app_control_get_channel_id(control));</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg) {</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%);">- snapshot = stasis_message_data(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_assert(snapshot != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(snapshot, +1);</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(msg, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return snapshot;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_channel_snapshot_get_latest(stasis_app_control_get_channel_id(control));</span><br><span> }</span><br><span> </span><br><span> static int app_send_command_on_condition(struct stasis_app_control *control,</span><br><span>diff --git a/tests/test_cel.c b/tests/test_cel.c</span><br><span>index 0b17d48..c1e7340 100644</span><br><span>--- a/tests/test_cel.c</span><br><span>+++ b/tests/test_cel.c</span><br><span>@@ -276,8 +276,7 @@</span><br><span> ast_hangup((channel)); \</span><br><span> HANGUP_EVENT(channel, cause, dialstatus); \</span><br><span> APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL); \</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_cleanup(stasis_cache_get(ast_channel_cache(), \</span><br><span style="color: hsl(0, 100%, 40%);">- ast_channel_snapshot_type(), ast_channel_uniqueid(channel))); \</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(ast_channel_snapshot_get_latest(ast_channel_uniqueid(channel))); \</span><br><span> ao2_cleanup(channel); \</span><br><span> channel = NULL; \</span><br><span> } while (0)</span><br><span>diff --git a/tests/test_stasis_endpoints.c b/tests/test_stasis_endpoints.c</span><br><span>index 9a49dd8..8408f36 100644</span><br><span>--- a/tests/test_stasis_endpoints.c</span><br><span>+++ b/tests/test_stasis_endpoints.c</span><br><span>@@ -255,32 +255,18 @@</span><br><span> ast_hangup(chan);</span><br><span> chan = NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- actual_count = stasis_message_sink_wait_for_count(sink, 6,</span><br><span style="color: hsl(120, 100%, 40%);">+ actual_count = stasis_message_sink_wait_for_count(sink, 3,</span><br><span> STASIS_SINK_DEFAULT_WAIT);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_test_validate(test, 6 == actual_count);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, 3 == actual_count);</span><br><span> </span><br><span> msg = sink->messages[1];</span><br><span> type = stasis_message_type(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_test_validate(test, stasis_cache_update_type() == type);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, ast_channel_snapshot_type() == type);</span><br><span> </span><br><span> msg = sink->messages[2];</span><br><span> type = stasis_message_type(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_test_validate(test, ast_channel_snapshot_type() == type);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- msg = sink->messages[3];</span><br><span style="color: hsl(0, 100%, 40%);">- type = stasis_message_type(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_test_validate(test, stasis_cache_update_type() == type);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* The ordering of the cache clear and endpoint snapshot are</span><br><span style="color: hsl(0, 100%, 40%);">- * unspecified */</span><br><span style="color: hsl(0, 100%, 40%);">- msg = sink->messages[4];</span><br><span style="color: hsl(0, 100%, 40%);">- if (stasis_message_type(msg) == stasis_cache_clear_type()) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Okay; the next message should be the endpoint snapshot */</span><br><span style="color: hsl(0, 100%, 40%);">- msg = sink->messages[5];</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%);">- type = stasis_message_type(msg);</span><br><span> ast_test_validate(test, ast_endpoint_snapshot_type() == type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> actual_snapshot = stasis_message_data(msg);</span><br><span> ast_test_validate(test, 0 == actual_snapshot->num_channels);</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/10478">change 10478</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/10478"/><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: I9334febff60a82d7c39703e49059fa3a68825786 </div>
<div style="display:none"> Gerrit-Change-Number: 10478 </div>
<div style="display:none"> Gerrit-PatchSet: 12 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Corey Farrell <git@cfware.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>