From: George Joseph Date: Fri, 6 Mar 2026 18:52:53 +0000 (-0700) Subject: rtp: Set RTPAUDIOQOS variables when ast_softhangup is called. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c2ee154ed2897a8461fd2f39733a4b4f4c627bd1;p=thirdparty%2Fasterisk.git rtp: Set RTPAUDIOQOS variables when ast_softhangup is called. If a channel in Stasis/ARI is hung up by the channel driver, the RTPAUDIOQOS variables are set before the channel leaves Stasis and are therefore available to the ARI app via ChannelVarset events. If the channel is hung up by ARI however, the channel leaves Stasis before the RTPAUDIOQOS variables are set so the app may not get the ChannelVarset events. We now set the RTPAUDIOQOS variables when ast_softhangup() is called as well as when the channel driver hangs up a channel. Since ARI hangups call ast_softhangup(), the variables will be set before the channel leaves Stasis and the app should get the ChannelVarset events. ast_rtp_instance_set_stats_vars(), which actually sets the variables, now checks to see if the variables are already set before attempting to set them. This prevents double messages from being generated. Resolves: #1816 --- diff --git a/main/channel.c b/main/channel.c index 76e7c3c787..ff2e38a343 100644 --- a/main/channel.c +++ b/main/channel.c @@ -75,6 +75,7 @@ #include "asterisk/max_forwards.h" #include "asterisk/stream.h" #include "asterisk/message.h" +#include "asterisk/rtp_engine.h" #include "channelstorage.h" @@ -2463,8 +2464,21 @@ int ast_softhangup(struct ast_channel *chan, int cause) RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref); int res; int tech_cause = 0; + struct ast_rtp_glue *glue; + RAII_VAR(struct ast_rtp_instance *, rtp, NULL, ao2_cleanup); + const struct ast_channel_tech *tech; ast_channel_lock(chan); + + tech = ast_channel_tech(chan); + glue = ast_rtp_instance_get_glue(tech->type); + if (glue) { + glue->get_rtp_info(chan, &rtp); + if (rtp) { + ast_rtp_instance_set_stats_vars(chan, rtp); + } + } + res = ast_softhangup_nolock(chan, cause); blob = ast_json_pack("{s: i, s: b}", "cause", cause, diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 90198e089d..b0c1bc2c42 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2704,14 +2704,36 @@ char *ast_rtp_instance_get_quality(struct ast_rtp_instance *instance, enum ast_r return buf; } +#define SET_STATS_VAR_HELPER(var_prefix, field) \ +({ \ + value = ast_rtp_instance_get_quality(instance, field, quality_buf, sizeof(quality_buf)); \ + if (value) { \ + if (!chanvars || ast_strlen_zero(ast_var_find(chanvars, var_prefix))) { \ + pbx_builtin_setvar_helper(chan, var_prefix, value); \ + chanchanges++; \ + } \ + if (bridge) { \ + if (!bridgevars || ast_strlen_zero(ast_var_find(bridgevars, var_prefix "BRIDGED"))) { \ + pbx_builtin_setvar_helper(bridge, var_prefix "BRIDGED", value); \ + bridgechanges++; \ + } \ + } \ + } \ +}) + void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_instance *instance) { char quality_buf[AST_MAX_USER_FIELD]; - char *quality; + char *value; struct ast_channel *bridge; + struct varshead *chanvars = ast_channel_varshead(chan); + struct varshead *bridgevars = NULL; + int chanchanges = 0; + int bridgechanges = 0; bridge = ast_channel_bridge_peer(chan); if (bridge) { + bridgevars = ast_channel_varshead(bridge); ast_channel_lock_both(chan, bridge); ast_channel_stage_snapshot(bridge); } else { @@ -2719,55 +2741,28 @@ void ast_rtp_instance_set_stats_vars(struct ast_channel *chan, struct ast_rtp_in } ast_channel_stage_snapshot(chan); - quality = ast_rtp_instance_get_quality(instance, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, - quality_buf, sizeof(quality_buf)); - if (quality) { - pbx_builtin_setvar_helper(chan, "RTPAUDIOQOS", quality); - if (bridge) { - pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSBRIDGED", quality); - } - } + SET_STATS_VAR_HELPER("RTPAUDIOQOS", AST_RTP_INSTANCE_STAT_FIELD_QUALITY); - quality = ast_rtp_instance_get_quality(instance, - AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER, quality_buf, sizeof(quality_buf)); - if (quality) { - pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSJITTER", quality); - if (bridge) { - pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSJITTERBRIDGED", quality); - } - } + SET_STATS_VAR_HELPER("RTPAUDIOQOSJITTER", AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER); - quality = ast_rtp_instance_get_quality(instance, - AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS, quality_buf, sizeof(quality_buf)); - if (quality) { - pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSLOSS", quality); - if (bridge) { - pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSLOSSBRIDGED", quality); - } - } + SET_STATS_VAR_HELPER("RTPAUDIOQOSLOSS", AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS); - quality = ast_rtp_instance_get_quality(instance, - AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT, quality_buf, sizeof(quality_buf)); - if (quality) { - pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSRTT", quality); - if (bridge) { - pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSRTTBRIDGED", quality); - } - } + SET_STATS_VAR_HELPER("RTPAUDIOQOSRTT", AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT); - quality = ast_rtp_instance_get_quality(instance, - AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES, quality_buf, sizeof(quality_buf)); - if (quality) { - pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSMES", quality); - if (bridge) { - pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSMESBRIDGED", quality); - } - } + SET_STATS_VAR_HELPER("RTPAUDIOQOSMES", AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES); - ast_channel_stage_snapshot_done(chan); + if (chanchanges) { + ast_channel_stage_snapshot_done(chan); + } else { + ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE); + } ast_channel_unlock(chan); if (bridge) { - ast_channel_stage_snapshot_done(bridge); + if (bridgechanges) { + ast_channel_stage_snapshot_done(bridge); + } else { + ast_clear_flag(ast_channel_flags(bridge), AST_FLAG_SNAPSHOT_STAGE); + } ast_channel_unlock(bridge); ast_channel_unref(bridge); }