Merge "app_confbridge: Add "all" variants of REMB behavior." into 16

This commit is contained in:
Joshua Colp
2019-05-03 10:53:21 -05:00
committed by Gerrit Code Review
8 changed files with 122 additions and 9 deletions

View File

@@ -1565,6 +1565,12 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen
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);
}
}

View File

@@ -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 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e,
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 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e,
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 @@ static int remb_behavior_handler(const struct aco_option *opt, struct ast_variab
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 @@ static int remb_behavior_handler(const struct aco_option *opt, struct ast_variab
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;
}

View File

@@ -82,6 +82,9 @@ enum bridge_profile_flags {
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 {

View File

@@ -1332,6 +1332,36 @@ static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_cha
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 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha
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 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha
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 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha
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 @@ static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct s
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 @@ static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct s
* 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 @@ static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct s
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 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
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,

View File

@@ -216,6 +216,8 @@ struct softmix_bridge_data {
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 {

View File

@@ -254,7 +254,11 @@ type=bridge
;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

View File

@@ -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..

View File

@@ -134,6 +134,12 @@ enum ast_bridge_video_sfu_remb_behavior {
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 */