diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index fbd1d1659a7937924bdcc0eaa13fb8cd49b24549..a6f8bded9c16701600cb7c654c1f3dddf323c355 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); @@ -828,6 +830,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 8ec9a236d4f3060409a873b37f48beaba85aa082..5e7b833c19b5bd34f2c19a8ea5dcdcea68175340 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);