diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index fca0ed6ef21f9a4651f3c3b8ff862fc38b31de0a..8ad188a5d8c4daab6b156fe04a1819f8df632198 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1730,6 +1730,9 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL); } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL)) { ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL); + } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_FORCE)) { + ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_FORCE); + ast_bridge_set_remb_estimated_bitrate(conference->bridge, conference->b_profile.remb_estimated_bitrate); } } diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 3814d30d69879243ccb075d662d710af1e13dbf2..656acc650f4bcc02ea5b7f2e261bca7635970d46 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -533,8 +533,22 @@ <para>The highest estimated maximum bitrate of all receivers in the bridge is taken and sent to each sender.</para> </enum> + <enum name="force"> + <para>The bitrate configured in <literal>remb_estimated_bitrate</literal> + is sent to each sender.</para> + </enum> </enumlist> </description> + <see-also><ref type="configOption">remb_estimated_bitrate</ref></see-also> + </configOption> + <configOption name="remb_estimated_bitrate"> + <synopsis>Sets the estimated bitrate sent to each participant in REMB reports</synopsis> + <description><para> + When <literal>remb_behavior</literal> is set to <literal>force</literal>, + this options sets the estimated bitrate (in bits per second) sent to each participant + in REMB reports. + </para></description> + <see-also><ref type="configOption">remb_behavior</ref></see-also> </configOption> <configOption name="enable_events" default="no"> <synopsis>Enables events for this bridge</synopsis> @@ -2159,7 +2173,9 @@ static int remb_behavior_handler(const struct aco_option *opt, struct ast_variab BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST | BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL | BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL | - BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL); + BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL | + BRIDGE_OPT_REMB_BEHAVIOR_FORCE + ); if (!strcasecmp(var->value, "average")) { ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE); @@ -2173,6 +2189,8 @@ static int remb_behavior_handler(const struct aco_option *opt, struct ast_variab ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL); } else if (!strcasecmp(var->value, "highest_all")) { ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL); + } else if (!strcasecmp(var->value, "force")) { + ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_FORCE); } else { return -1; } @@ -2419,6 +2437,7 @@ int conf_load_config(void) aco_option_register(&cfg_info, "video_update_discard", ACO_EXACT, bridge_types, "2000", OPT_UINT_T, 0, FLDSET(struct bridge_profile, video_update_discard)); aco_option_register(&cfg_info, "remb_send_interval", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_send_interval)); aco_option_register_custom(&cfg_info, "remb_behavior", ACO_EXACT, bridge_types, "average", remb_behavior_handler, 0); + aco_option_register(&cfg_info, "remb_estimated_bitrate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_estimated_bitrate)); aco_option_register(&cfg_info, "enable_events", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_ENABLE_EVENTS); /* This option should only be used with the CONFBRIDGE dialplan function */ aco_option_register_custom(&cfg_info, "template", ACO_EXACT, bridge_types, NULL, bridge_template_handler, 0); diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index e48292a0ba155a5f21e9d4e33dc2c9976a12d735..f4133593578cd446b9a7c25867122a987beb35ae 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -87,6 +87,7 @@ enum bridge_profile_flags { BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL = (1 << 12), /*!< The average of all REMB reports in the entire bridge is sent to each sender */ BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL = (1 << 13), /*!< The lowest estimated maximum bitrate from all receivers is sent to each sender */ BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL = (1 << 14), /*!< The highest estimated maximum bitrate from all receivers is sent to each sender */ + BRIDGE_OPT_REMB_BEHAVIOR_FORCE = (1 << 15), /*!< Force the REMB estimated bitrate to that specifiec in remb_estimated_bitrate */ }; enum conf_menu_action_id { @@ -235,6 +236,7 @@ struct bridge_profile { char regcontext[AST_MAX_CONTEXT]; unsigned int video_update_discard; /*!< Amount of time after sending a video update request that subsequent requests should be discarded */ unsigned int remb_send_interval; /*!< Interval at which a combined REMB frame is sent to video sources */ + unsigned int remb_estimated_bitrate; /*!< Bitrate sent when BRIDGE_OPT_REMB_BEHAVIOR_FORCE is set */ }; /*! \brief The structure that represents a conference bridge */ diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index 5acd7943b09e15484084bea7d20d7b5349dd1258..d51a55f7d1f59ac5bf6ed7fe4558df80c0cd1d01 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -1396,6 +1396,7 @@ static void remb_collect_report_all(struct ast_bridge *bridge, struct softmix_br case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE: case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST: case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST: + case AST_BRIDGE_VIDEO_SFU_REMB_FORCE: /* These will never actually get hit due to being handled by remb_collect_report below */ break; } @@ -1417,6 +1418,12 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha /* We evenly divide the available maximum bitrate across the video sources * to this receiver so each source gets an equal slice. */ + + if (bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_FORCE) { + softmix_data->bitrate = bridge->softmix.video_mode.mode_data.sfu_data.estimated_bitrate; + return; + } + bitrate = (sc->remb.br_mantissa << sc->remb.br_exp) / AST_VECTOR_SIZE(&sc->video_sources); /* If this receiver has no bitrate yet ignore it */ @@ -1462,6 +1469,9 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL: /* These will never actually get hit due to being handled by remb_collect_report_all above */ break; + case AST_BRIDGE_VIDEO_SFU_REMB_FORCE: + /* Don't do anything, we've already forced it */ + break; } } diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample index 02edaa538ddeb3ed78c6ff6446724d74148b9815..7749c93ef7827cf2f3155e404ec8d133eca1213b 100644 --- a/configs/samples/confbridge.conf.sample +++ b/configs/samples/confbridge.conf.sample @@ -264,8 +264,11 @@ type=bridge ; the highest maximum bitrate is forwarded to the sender. If set to "average_all" a single average ; is generated from every receiver and the same value is sent to every sender. If set to ; "lowest_all" the lowest maximum bitrate of all receivers is sent to every sender. If set to - ; "highest_all" the highest maximum bitrate of all receivers is sent to every sender. This - ; defaults to "average". + ; "highest_all" the highest maximum bitrate of all receivers is sent to every sender. + ; When set to "force", the value set in remb_estimated_bitrate is sent to every sender. + ; This defaults to "average". +;remb_estimated_bitrate=0 ; When remb_behavior is set to 'force', this options sets the estimated bitrate + ; (in bits per second) sent to each participant in REMB reports. ;enable_events=no ; If enabled, recipients who joined the bridge via a channel driver ; that supports Enhanced Messaging (currently only chan_pjsip) will diff --git a/doc/CHANGES-staging/app_confbridge.txt b/doc/CHANGES-staging/app_confbridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..092e392f5dd35197c0e3c74c34d744cea058452e --- /dev/null +++ b/doc/CHANGES-staging/app_confbridge.txt @@ -0,0 +1,7 @@ +Subject: app_confbridge + +app_confbridge now has the ability to force the estimated bitrate on an SFU +bridge. To use it, set a bridge profile's remb_behavior to "force" and +set remb_estimated_bitrate to a rate in bits per second. The +remb_estimated_bitrate parameter is ignored if remb_behavior is something +other than "force". diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index a0aa4c5d7689697909588de1f49d38726feb22da..6a7a3956358178166f64921ba3de49d655c4802f 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -141,6 +141,8 @@ enum ast_bridge_video_sfu_remb_behavior { AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL, /*! The highest reported bitrate from all channels in the bridge is forwarded to each sender */ AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL, + /*! Force the REMB estimated bitrate to a specified value */ + AST_BRIDGE_VIDEO_SFU_REMB_FORCE, }; /*! \brief This is used for selective forwarding unit configuration */ @@ -149,6 +151,8 @@ struct ast_bridge_video_sfu_data { unsigned int remb_send_interval; /*! How the combined REMB report is generated */ enum ast_bridge_video_sfu_remb_behavior remb_behavior; + /*! The estimated bitrate when behavior is "force" */ + float estimated_bitrate; }; /*! \brief Data structure that defines a video source mode */ @@ -1039,6 +1043,16 @@ void ast_bridge_set_remb_send_interval(struct ast_bridge *bridge, unsigned int r */ void ast_brige_set_remb_behavior(struct ast_bridge *bridge, enum ast_bridge_video_sfu_remb_behavior behavior); +/*! + * \brief Force the REMB report estimated bitrate to a specific max value + * + * \param bridge Bridge to set the REMB behavior on + * \param estimated_bitrate The estimated bitrate in bits per second + * + * \note This can only be called when the bridge has been set to the SFU video mode. + */ +void ast_bridge_set_remb_estimated_bitrate(struct ast_bridge *bridge, float estimated_bitrate); + /*! * \brief Update information about talker energy for talker src video mode. */ diff --git a/main/bridge.c b/main/bridge.c index d44f6596e250322f12408a948992891d73754605..05380085d3d36a7dbdd405ba2274a97fbf0c54e4 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -3871,6 +3871,15 @@ void ast_brige_set_remb_behavior(struct ast_bridge *bridge, enum ast_bridge_vide ast_bridge_unlock(bridge); } +void ast_bridge_set_remb_estimated_bitrate(struct ast_bridge *bridge, float estimated_bitrate) +{ + ast_assert(bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU); + + ast_bridge_lock(bridge); + bridge->softmix.video_mode.mode_data.sfu_data.estimated_bitrate = estimated_bitrate; + ast_bridge_unlock(bridge); +} + void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyframe) { struct ast_bridge_video_talker_src_data *data;