Commit ff34444a4b for asterisk.org

commit ff34444a4b04b85077fba66f30d4a2b782b30baa
Author: Joshua C. Colp <jcolp@sangoma.com>
Date:   Tue Feb 10 10:33:53 2026 -0400

    endpoints: Allow access to latest snapshot directly.

    This change adds an API call to allow direct access to the latest
    snapshot of an ast_endpoint. This is then used by chan_pjsip when
    calculating device state, eliminating the need to access the cache
    which would incur a container find and access.

diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index f44c51edae..4fc39d1acc 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -1188,9 +1188,7 @@ static int chan_pjsip_devicestate(const char *data)
 		return AST_DEVICE_INVALID;
 	}

-	endpoint_snapshot = ast_endpoint_latest_snapshot(ast_endpoint_get_tech(endpoint->persistent),
-		ast_endpoint_get_resource(endpoint->persistent));
-
+	endpoint_snapshot = ast_endpoint_get_snapshot(endpoint->persistent);
 	if (!endpoint_snapshot) {
 		return AST_DEVICE_INVALID;
 	}
diff --git a/include/asterisk/endpoints.h b/include/asterisk/endpoints.h
index 0be9d352ba..1835cbc37f 100644
--- a/include/asterisk/endpoints.h
+++ b/include/asterisk/endpoints.h
@@ -169,6 +169,18 @@ const char *ast_endpoint_get_id(const struct ast_endpoint *endpoint);
  */
 enum ast_endpoint_state ast_endpoint_get_state(const struct ast_endpoint *endpoint);

+/*!
+ * \brief Gets the latest snapshot of the given endpoint.
+ *
+ * \param endpoint The endpoint.
+ * \return Latest snapshot of the endpoint.
+ * \retval NULL if endpoint is \c NULL.
+ * \since 20.19.0
+ * \since 22.9.0
+ * \since 23.3.0
+ */
+struct ast_endpoint_snapshot *ast_endpoint_get_snapshot(struct ast_endpoint *endpoint);
+
 /*!
  * \brief Updates the state of the given endpoint.
  *
diff --git a/main/endpoints.c b/main/endpoints.c
index 15691b239d..5300b52f4f 100644
--- a/main/endpoints.c
+++ b/main/endpoints.c
@@ -71,6 +71,8 @@ struct ast_endpoint {
 	struct ao2_container *channel_ids;
 	/*! Forwarding subscription from an endpoint to its tech endpoint */
 	struct stasis_forward *tech_forward;
+	/*! The latest snapshot of the endpoint */
+	struct ast_endpoint_snapshot *snapshot;
 };

 AO2_STRING_FIELD_HASH_FN(ast_endpoint, id)
@@ -137,6 +139,10 @@ static void endpoint_publish_snapshot(struct ast_endpoint *endpoint)
 		return;
 	}
 	stasis_publish(ast_endpoint_topic(endpoint), message);
+
+	ao2_lock(endpoint);
+	ao2_replace(endpoint->snapshot, snapshot);
+	ao2_unlock(endpoint);
 }

 static void endpoint_dtor(void *obj)
@@ -149,6 +155,9 @@ static void endpoint_dtor(void *obj)
 	ao2_cleanup(endpoint->channel_ids);
 	endpoint->channel_ids = NULL;

+	ao2_cleanup(endpoint->snapshot);
+	endpoint->snapshot = NULL;
+
 	ast_string_field_free_memory(endpoint);
 }

@@ -362,6 +371,21 @@ enum ast_endpoint_state ast_endpoint_get_state(const struct ast_endpoint *endpoi
 	return endpoint->state;
 }

+struct ast_endpoint_snapshot *ast_endpoint_get_snapshot(struct ast_endpoint *endpoint)
+{
+	struct ast_endpoint_snapshot *snapshot;
+
+	if (!endpoint) {
+		return NULL;
+	}
+
+	ao2_lock(endpoint);
+	snapshot = ao2_bump(endpoint->snapshot);
+	ao2_unlock(endpoint);
+
+	return snapshot;
+}
+
 void ast_endpoint_set_state(struct ast_endpoint *endpoint,
 	enum ast_endpoint_state state)
 {