From 7e1d881d89d492b009afd68dd014cf828652ab5e Mon Sep 17 00:00:00 2001
From: Sungtae Kim <sungtae@messagebird.com>
Date: Tue, 22 Jan 2019 13:02:50 +0100
Subject: [PATCH] res_pjsip_session Added rtcp stats result vector into the
 session

Currently, the Asterisk's pjsip_session module does not keeping the
rtcp's stats info after it was removed. But by adding the results
vector and keeping it until session is destroying, it can give more
useful information for other modules.

ASTERISK-28253

Change-Id: Ib25c2d3fc4da084aecfde2a82c1b1d733bd64fa5
---
 include/asterisk/res_pjsip_session.h |  9 +++++
 res/res_pjsip_session.c              | 54 ++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index 34f4783541..6e23f8eab3 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -215,6 +215,8 @@ struct ast_sip_session {
 	enum ast_sip_dtmf_mode dtmf;
 	/*! Initial incoming INVITE Request-URI.  NULL otherwise. */
 	pjsip_uri *request_uri;
+	/* Media statistics for negotiated RTP streams */
+	AST_VECTOR(, struct ast_rtp_instance_stats *) media_stats;
 };
 
 typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
@@ -830,6 +832,13 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void);
 struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,
 	struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position);
 
+/*!
+ * \brief Save a media stats.
+ *
+ * \param media_state The media state to save
+ */
+void ast_sip_session_media_stats_save(struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state);
+
 /*!
  * \brief Reset a media state to a clean state
  * \since 15.0.0
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 99e0ca4ff5..52db333e6e 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -48,6 +48,7 @@
 #include "asterisk/pickup.h"
 #include "asterisk/test.h"
 #include "asterisk/stream.h"
+#include "asterisk/vector.h"
 
 #define SDP_HANDLER_BUCKETS 11
 
@@ -176,6 +177,16 @@ void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *
 	ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler);
 }
 
+static int media_stats_local_ssrc_cmp(
+		const struct ast_rtp_instance_stats *vec_elem, const struct ast_rtp_instance_stats *srch)
+{
+	if (vec_elem->local_ssrc == srch->local_ssrc) {
+		return 1;
+	}
+
+	return 0;
+}
+
 static struct ast_sip_session_media_state *internal_sip_session_media_state_alloc(
 	size_t sessions, size_t read_callbacks)
 {
@@ -206,6 +217,40 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void)
 		DEFAULT_NUM_SESSION_MEDIA, DEFAULT_NUM_SESSION_MEDIA);
 }
 
+void ast_sip_session_media_stats_save(struct ast_sip_session *sip_session, struct ast_sip_session_media_state *media_state)
+{
+	int i;
+	int ret;
+
+	if (!media_state || !sip_session) {
+		return;
+	}
+
+	for (i = 0; i < AST_VECTOR_SIZE(&media_state->sessions); i++) {
+		struct ast_rtp_instance_stats *stats_tmp = NULL;
+		struct ast_sip_session_media *media = AST_VECTOR_GET(&media_state->sessions, i);
+		if (!media || !media->rtp) {
+			continue;
+		}
+
+		stats_tmp = ast_calloc(1, sizeof(struct ast_rtp_instance_stats));
+		if (!stats_tmp) {
+			return;
+		}
+
+		ret = ast_rtp_instance_get_stats(media->rtp, stats_tmp, AST_RTP_INSTANCE_STAT_ALL);
+		if (ret) {
+			ast_free(stats_tmp);
+			continue;
+		}
+
+		/* remove all the duplicated stats if exist */
+		AST_VECTOR_REMOVE_CMP_UNORDERED(&sip_session->media_stats, stats_tmp, media_stats_local_ssrc_cmp, ast_free);
+
+		AST_VECTOR_APPEND(&sip_session->media_stats, stats_tmp);
+	}
+}
+
 void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
 {
 	int index;
@@ -1010,6 +1055,7 @@ static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_
 	}
 
 	/* Active and pending flip flop as needed */
+	ast_sip_session_media_stats_save(session, session->active_media_state);
 	SWAP(session->active_media_state, session->pending_media_state);
 	ast_sip_session_media_state_reset(session->pending_media_state);
 
@@ -2113,6 +2159,10 @@ static void session_destructor(void *obj)
 	ast_sip_session_remove_supplements(session);
 	AST_LIST_HEAD_DESTROY(&session->supplements);
 
+	/* remove all saved media stats */
+	AST_VECTOR_RESET(&session->media_stats, ast_free);
+	AST_VECTOR_FREE(&session->media_stats);
+
 	ast_taskprocessor_unreference(session->serializer);
 	ao2_cleanup(session->datastores);
 	ast_sip_session_media_state_free(session->active_media_state);
@@ -2194,6 +2244,9 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
 	if (!session->pending_media_state) {
 		return NULL;
 	}
+	if (AST_VECTOR_INIT(&session->media_stats, 1) < 0) {
+		return NULL;
+	}
 
 	if (endpoint->dtmf == AST_SIP_DTMF_INBAND || endpoint->dtmf == AST_SIP_DTMF_AUTO) {
 		dsp_features |= DSP_FEATURE_DIGIT_DETECT;
@@ -2637,6 +2690,7 @@ void ast_sip_session_terminate(struct ast_sip_session *session, int response)
 	 * places when the session is to be terminated we terminate any existing
 	 * media sessions here.
 	 */
+	ast_sip_session_media_stats_save(session, session->active_media_state);
 	SWAP(session->active_media_state, session->pending_media_state);
 	ast_sip_session_media_state_reset(session->pending_media_state);
 
-- 
GitLab