]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
rtp: Set RTPAUDIOQOS variables when ast_softhangup is called.
authorGeorge Joseph <gjoseph@sangoma.com>
Fri, 6 Mar 2026 18:52:53 +0000 (11:52 -0700)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Tue, 10 Mar 2026 13:49:00 +0000 (13:49 +0000)
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

main/channel.c
main/rtp_engine.c

index 76e7c3c78796e93553c100b47e7d98362515358d..ff2e38a343171aa7890891068875f76aeac31092 100644 (file)
@@ -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,
index 90198e089d84eef79cc847428a5ffd29253c877f..b0c1bc2c42abd19deb87cff6ad0c6623d6c2f2fd 100644 (file)
@@ -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);
        }