[Asterisk-code-review] app_confbridge: Add "all" variants of REMB behavior. (...asterisk[16])

Joshua Colp asteriskteam at digium.com
Fri May 3 10:53:21 CDT 2019


Joshua Colp has submitted this change and it was merged. ( https://gerrit.asterisk.org/c/asterisk/+/11321 )

Change subject: app_confbridge: Add "all" variants of REMB behavior.
......................................................................

app_confbridge: Add "all" variants of REMB behavior.

When producing a combined REMB value the normal behavior
is to have a REMB value which is unique for each sender
based on all of their receivers. This can result in one
sender having low bitrate while all the rest are high.

This change adds "all" variants which produces a bridge
level REMB value instead. All REMB reports are combined
together into a single REMB value that is the same for
each sender.

ASTERISK-28401

Change-Id: I883e6cc26003b497c8180b346111c79a131ba88c
---
M apps/app_confbridge.c
M apps/confbridge/conf_config_parser.c
M apps/confbridge/include/confbridge.h
M bridges/bridge_softmix.c
M bridges/bridge_softmix/include/bridge_softmix_internal.h
M configs/samples/confbridge.conf.sample
A doc/CHANGES-staging/app_confbridge_remb_behavior_all.txt
M include/asterisk/bridge.h
8 files changed, 122 insertions(+), 9 deletions(-)

Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved
  Joshua Colp: Approved for Submit



diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
index 33cfbb3..6d141bd 100644
--- a/apps/app_confbridge.c
+++ b/apps/app_confbridge.c
@@ -1565,6 +1565,12 @@
 				ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST);
 			} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST)) {
 				ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST);
+			} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL)) {
+				ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL);
+			} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL)) {
+				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);
 			}
 		}
 
diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c
index 53061ba..f732c45 100644
--- a/apps/confbridge/conf_config_parser.c
+++ b/apps/confbridge/conf_config_parser.c
@@ -505,6 +505,18 @@
 							<enum name="highest">
 								<para>The highest estimated maximum bitrate is forwarded to the sender.</para>
 							</enum>
+							<enum name="average_all">
+								<para>The average of all estimated maximum bitrates is taken from all
+								receivers in the bridge and a single value is sent to each sender.</para>
+							</enum>
+							<enum name="lowest_all">
+								<para>The lowest estimated maximum bitrate of all receivers in the bridge
+								is taken and sent to each sender.</para>
+							</enum>
+							<enum name="highest_all">
+								<para>The highest estimated maximum bitrate of all receivers in the bridge
+								is taken and sent to each sender.</para>
+							</enum>
 						</enumlist>
 					</description>
 				</configOption>
@@ -1737,7 +1749,8 @@
 
 	switch (b_profile.flags
 		& (BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE | BRIDGE_OPT_REMB_BEHAVIOR_LOWEST
-			| BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST)) {
+			| BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST | BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL
+			| BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL | BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL)) {
 	case BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE:
 		ast_cli(a->fd, "REMB Behavior:           average\n");
 		break;
@@ -1747,6 +1760,15 @@
 	case BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST:
 		ast_cli(a->fd, "REMB Behavior:           highest\n");
 		break;
+	case BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL:
+		ast_cli(a->fd, "REMB Behavior:           average_all\n");
+		break;
+	case BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL:
+		ast_cli(a->fd, "REMB Behavior:           lowest_all\n");
+		break;
+	case BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL:
+		ast_cli(a->fd, "REMB Behavior:           highest_all\n");
+		break;
 	default:
 		ast_assert(0);
 		break;
@@ -2108,7 +2130,10 @@
 
 	ast_clear_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE |
 		BRIDGE_OPT_REMB_BEHAVIOR_LOWEST |
-		BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST);
+		BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST |
+		BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL |
+		BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL |
+		BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL);
 
 	if (!strcasecmp(var->value, "average")) {
 		ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE);
@@ -2116,6 +2141,12 @@
 		ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST);
 	} else if (!strcasecmp(var->value, "highest")) {
 		ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST);
+	} else if (!strcasecmp(var->value, "average_all")) {
+		ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL);
+	} else if (!strcasecmp(var->value, "lowest_all")) {
+		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 {
 		return -1;
 	}
diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
index 4b8249f..237431e 100644
--- a/apps/confbridge/include/confbridge.h
+++ b/apps/confbridge/include/confbridge.h
@@ -82,6 +82,9 @@
 	BRIDGE_OPT_REMB_BEHAVIOR_LOWEST = (1 << 9), /*!< The lowest estimated maximum bitrate is sent to the sender */
 	BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST = (1 << 10), /*!< The highest estimated maximum bitrate is sent to the sender */
 	BRIDGE_OPT_ENABLE_EVENTS = (1 << 11), /*!< Enable sending events to participants */
+	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 */
 };
 
 enum conf_menu_action_id {
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index f9f8520..a90c716 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -1332,6 +1332,36 @@
 	return res;
 }
 
+static void remb_collect_report_all(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data,
+	float bitrate)
+{
+	if (!softmix_data->bitrate) {
+		softmix_data->bitrate = bitrate;
+		return;
+	}
+
+	switch (bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior) {
+	case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL:
+		softmix_data->bitrate = (softmix_data->bitrate + bitrate) / 2;
+		break;
+	case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL:
+		if (bitrate < softmix_data->bitrate) {
+			softmix_data->bitrate = bitrate;
+		}
+		break;
+	case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL:
+		if (bitrate > softmix_data->bitrate) {
+			softmix_data->bitrate = bitrate;
+		}
+		break;
+	case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE:
+	case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST:
+	case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST:
+		/* These will never actually get hit due to being handled by remb_collect_report below */
+		break;
+	}
+}
+
 static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel,
 	struct softmix_bridge_data *softmix_data, struct softmix_channel *sc)
 {
@@ -1355,6 +1385,14 @@
 		return;
 	}
 
+	/* If we are using the "all" variants then we should use the bridge bitrate to store information */
+	if (bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL ||
+		bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL ||
+		bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL) {
+		remb_collect_report_all(bridge, softmix_data, bitrate);
+		return;
+	}
+
 	for (i = 0; i < AST_VECTOR_SIZE(&sc->video_sources); ++i) {
 		struct softmix_remb_collector *collector;
 
@@ -1380,6 +1418,11 @@
 				collector->bitrate = bitrate;
 			}
 			break;
+		case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL:
+		case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL:
+		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;
 		}
 	}
 
@@ -1390,8 +1433,10 @@
 	sc->remb.br_exp = 0;
 }
 
-static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct softmix_channel *sc)
+static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct softmix_bridge_data *softmix_data,
+	struct softmix_channel *sc)
 {
+	float bitrate = softmix_data->bitrate;
 	int i;
 	int exp;
 
@@ -1399,6 +1444,12 @@
 		return;
 	}
 
+	/* If there is no bridge level bitrate fall back to collector level */
+	if (!bitrate) {
+		bitrate = sc->remb_collector->bitrate;
+		sc->remb_collector->bitrate = 0;
+	}
+
 	/* We always do this calculation as even when the bitrate is zero the browser
 	 * still prefers it to be accurate instead of lying.
 	 *
@@ -1442,10 +1493,10 @@
 	 * Precision on the "lower" end is lost due to zeros being shifted in. This loss is
 	 * both expected and acceptable.
 	 */
-	frexp(sc->remb_collector->bitrate, &exp);
+	frexp(bitrate, &exp);
 	exp = exp > 18 ? exp - 18 : 0;
 
-	sc->remb_collector->feedback.remb.br_mantissa = sc->remb_collector->bitrate / (1 << exp);
+	sc->remb_collector->feedback.remb.br_mantissa = bitrate / (1 << exp);
 	sc->remb_collector->feedback.remb.br_exp = exp;
 
 	for (i = 0; i < AST_VECTOR_SIZE(&bridge_channel->stream_map.to_bridge); ++i) {
@@ -1466,8 +1517,6 @@
 		sc->remb_collector->frame.stream_num = bridge_num;
 		ast_bridge_channel_queue_frame(bridge_channel, &sc->remb_collector->frame);
 	}
-
-	sc->remb_collector->bitrate = 0;
 }
 
 static void gather_softmix_stats(struct softmix_stats *stats,
@@ -1827,10 +1876,15 @@
 			ast_bridge_channel_queue_frame(bridge_channel, &sc->write_frame);
 
 			if (remb_update) {
-				remb_send_report(bridge_channel, sc);
+				remb_send_report(bridge_channel, softmix_data, sc);
 			}
 		}
 
+		if (remb_update) {
+			/* In case we are doing bridge level REMB reset the bitrate so we start fresh */
+			softmix_data->bitrate = 0;
+		}
+
 		update_all_rates = 0;
 		if (!stat_iteration_counter) {
 			update_all_rates = analyse_softmix_stats(&stats, softmix_data,
diff --git a/bridges/bridge_softmix/include/bridge_softmix_internal.h b/bridges/bridge_softmix/include/bridge_softmix_internal.h
index 15856b3..ca70c3c 100644
--- a/bridges/bridge_softmix/include/bridge_softmix_internal.h
+++ b/bridges/bridge_softmix/include/bridge_softmix_internal.h
@@ -216,6 +216,8 @@
 	struct timeval last_remb_update;
 	/*! Per-bridge stream REMB collectors, which flow back to video source */
 	AST_VECTOR(, struct softmix_remb_collector *) remb_collectors;
+	/*! Per-bridge REMB bitrate */
+	float bitrate;
 };
 
 struct softmix_mixing_array {
diff --git a/configs/samples/confbridge.conf.sample b/configs/samples/confbridge.conf.sample
index a214f34..e148181 100644
--- a/configs/samples/confbridge.conf.sample
+++ b/configs/samples/confbridge.conf.sample
@@ -254,7 +254,11 @@
 ;remb_behavior=average     ; How the combined REMB report for an SFU video bridge is constructed. If set to "average" then
                            ; the estimated maximum bitrate of each receiver is used to construct an average bitrate. If
                            ; set to "lowest" the lowest maximum bitrate is forwarded to the sender. If set to "highest"
-                           ; the highest maximum bitrate is forwarded to the sender. This defaults to "average".
+                           ; 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".
 
 ;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_remb_behavior_all.txt b/doc/CHANGES-staging/app_confbridge_remb_behavior_all.txt
new file mode 100644
index 0000000..6110a6f
--- /dev/null
+++ b/doc/CHANGES-staging/app_confbridge_remb_behavior_all.txt
@@ -0,0 +1,7 @@
+Subject: ConfBridge
+
+Add "average_all", "highest_all", and "lowest_all" values for
+the remb_behavior option. These values operate on a bridge
+level instead of a per-source level. This means that a single
+REMB value is calculated and sent to every sender, instead of
+a REMB value that is unique for the specific sender..
diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h
index dc8ebe5..43ecb3e 100644
--- a/include/asterisk/bridge.h
+++ b/include/asterisk/bridge.h
@@ -134,6 +134,12 @@
 	AST_BRIDGE_VIDEO_SFU_REMB_LOWEST,
 	/*! The highest reported bitrate is forwarded to the sender */
 	AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST,
+	/*! The average of all reports WITHIN the bridge is sent to each sender */
+	AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL,
+	/*! The lowest reported bitrate from all channels in the bridge is forwarded to each sender */
+	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,
 };
 
 /*! \brief This is used for selective forwarding unit configuration */

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/11321
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 16
Gerrit-Change-Id: I883e6cc26003b497c8180b346111c79a131ba88c
Gerrit-Change-Number: 11321
Gerrit-PatchSet: 3
Gerrit-Owner: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Benjamin Keith Ford <bford at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: Sean Bright <sean.bright at gmail.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190503/6e439d89/attachment-0001.html>


More information about the asterisk-code-review mailing list