Add functionality to set min/max bitrate per simulcast layer through RtpEncodingParameters.
Target bitrate is set to 0.75 of the max bitrate. Bug: webrtc:9341, webrtc:8655 Change-Id: I9a8c8bb95bb1532d45f05578832418464452340e Reviewed-on: https://webrtc-review.googlesource.com/79821 Commit-Queue: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23676}
This commit is contained in:
@ -401,14 +401,6 @@ struct RtpEncodingParameters {
|
||||
// bitrate. Currently this is implemented for the entire rtp sender by using
|
||||
// the value of the first encoding parameter.
|
||||
//
|
||||
// TODO(webrtc.bugs.org/8655): Implement this per encoding parameter.
|
||||
// Current implementation for a sender:
|
||||
// The max bitrate is decided by taking the minimum of the first encoding
|
||||
// parameter's max_bitrate_bps and the max bitrate specified by the sdp with
|
||||
// the b=AS attribute. In the case of simulcast video, default values are used
|
||||
// for each simulcast layer, and if there is some bitrate left over from the
|
||||
// sender's max bitrate then it will roll over into the highest quality layer.
|
||||
//
|
||||
// Just called "maxBitrate" in ORTC spec.
|
||||
//
|
||||
// TODO(deadbeef): With ORTC RtpSenders, this currently sets the total
|
||||
@ -417,7 +409,9 @@ struct RtpEncodingParameters {
|
||||
// fixed.
|
||||
rtc::Optional<int> max_bitrate_bps;
|
||||
|
||||
// TODO(asapersson): Not implemented.
|
||||
// Specifies the minimum bitrate in bps for video.
|
||||
// TODO(asapersson): Not implemented for ORTC API.
|
||||
// TODO(asapersson): Not implemented for single layer.
|
||||
rtc::Optional<int> min_bitrate_bps;
|
||||
|
||||
// TODO(deadbeef): Not implemented.
|
||||
|
@ -57,6 +57,7 @@ class RtpSenderInterface : public rtc::RefCountInterface {
|
||||
virtual RtpParameters GetParameters() = 0;
|
||||
// Note that only a subset of the parameters can currently be changed. See
|
||||
// rtpparameters.h
|
||||
// The encodings are in increasing quality order for simulcast.
|
||||
virtual RTCError SetParameters(const RtpParameters& parameters) = 0;
|
||||
|
||||
// Returns null for a video sender.
|
||||
|
@ -151,6 +151,9 @@ void SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) {
|
||||
|
||||
void BoostMaxSimulcastLayer(int max_bitrate_bps,
|
||||
std::vector<webrtc::VideoStream>* layers) {
|
||||
if (layers->empty())
|
||||
return;
|
||||
|
||||
// Spend additional bits to boost the max layer.
|
||||
int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(*layers);
|
||||
if (bitrate_left_bps > 0) {
|
||||
@ -159,6 +162,9 @@ void BoostMaxSimulcastLayer(int max_bitrate_bps,
|
||||
}
|
||||
|
||||
int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& layers) {
|
||||
if (layers.empty())
|
||||
return 0;
|
||||
|
||||
int total_max_bitrate_bps = 0;
|
||||
for (size_t s = 0; s < layers.size() - 1; ++s) {
|
||||
total_max_bitrate_bps += layers[s].target_bitrate_bps;
|
||||
@ -170,18 +176,18 @@ int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& layers) {
|
||||
std::vector<webrtc::VideoStream> GetSimulcastConfig(size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
int max_bitrate_bps,
|
||||
int /*max_bitrate_bps*/,
|
||||
double bitrate_priority,
|
||||
int max_qp,
|
||||
int max_framerate,
|
||||
bool is_screenshare) {
|
||||
if (is_screenshare) {
|
||||
return GetScreenshareLayers(max_layers, width, height, max_bitrate_bps,
|
||||
bitrate_priority, max_qp, max_framerate,
|
||||
return GetScreenshareLayers(max_layers, width, height, bitrate_priority,
|
||||
max_qp, max_framerate,
|
||||
ScreenshareSimulcastFieldTrialEnabled());
|
||||
} else {
|
||||
return GetNormalSimulcastLayers(max_layers, width, height, max_bitrate_bps,
|
||||
bitrate_priority, max_qp, max_framerate);
|
||||
return GetNormalSimulcastLayers(max_layers, width, height, bitrate_priority,
|
||||
max_qp, max_framerate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +195,6 @@ std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
|
||||
size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
int max_bitrate_bps,
|
||||
double bitrate_priority,
|
||||
int max_qp,
|
||||
int max_framerate) {
|
||||
@ -249,8 +254,6 @@ std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If there is bitrate leftover, give it to the largest layer.
|
||||
BoostMaxSimulcastLayer(max_bitrate_bps, &layers);
|
||||
// Currently the relative bitrate priority of the sender is controlled by
|
||||
// the value of the lowest VideoStream.
|
||||
// TODO(bugs.webrtc.org/8630): The web specification describes being able to
|
||||
@ -264,7 +267,6 @@ std::vector<webrtc::VideoStream> GetScreenshareLayers(
|
||||
size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
int max_bitrate_bps,
|
||||
double bitrate_priority,
|
||||
int max_qp,
|
||||
int max_framerate,
|
||||
|
@ -21,35 +21,39 @@ namespace cricket {
|
||||
// TODO(pthatcher): Write unit tests just for these functions,
|
||||
// independent of WebrtcVideoEngine.
|
||||
|
||||
// Gets the total maximum bitrate for the |streams|.
|
||||
int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& streams);
|
||||
|
||||
// Get simulcast settings.
|
||||
std::vector<webrtc::VideoStream> GetSimulcastConfig(
|
||||
size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
int max_bitrate_bps,
|
||||
double bitrate_priority,
|
||||
int max_qp,
|
||||
int max_framerate,
|
||||
bool is_screenshare);
|
||||
// Adds any bitrate of |max_bitrate_bps| that is above the total maximum bitrate
|
||||
// for the |layers| to the highest quality layer.
|
||||
void BoostMaxSimulcastLayer(int max_bitrate_bps,
|
||||
std::vector<webrtc::VideoStream>* layers);
|
||||
|
||||
// Gets simulcast settings.
|
||||
// TODO(asapersson): Remove max_bitrate_bps.
|
||||
std::vector<webrtc::VideoStream> GetSimulcastConfig(size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
int /*max_bitrate_bps*/,
|
||||
double bitrate_priority,
|
||||
int max_qp,
|
||||
int max_framerate,
|
||||
bool is_screenshare);
|
||||
|
||||
// Gets the simulcast config layers for a non-screensharing case.
|
||||
std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
|
||||
size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
int max_bitrate_bps,
|
||||
double bitrate_priority,
|
||||
int max_qp,
|
||||
int max_framerate);
|
||||
|
||||
// Get simulcast config layers for screenshare settings.
|
||||
// Gets simulcast config layers for screenshare settings.
|
||||
std::vector<webrtc::VideoStream> GetScreenshareLayers(
|
||||
size_t max_layers,
|
||||
int width,
|
||||
int height,
|
||||
int max_bitrate_bps,
|
||||
double bitrate_priority,
|
||||
int max_qp,
|
||||
int max_framerate,
|
||||
|
@ -1800,13 +1800,23 @@ webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
|
||||
return error;
|
||||
}
|
||||
|
||||
bool new_bitrate = false;
|
||||
for (size_t i = 0; i < rtp_parameters_.encodings.size(); ++i) {
|
||||
if ((new_parameters.encodings[i].min_bitrate_bps !=
|
||||
rtp_parameters_.encodings[i].min_bitrate_bps) ||
|
||||
(new_parameters.encodings[i].max_bitrate_bps !=
|
||||
rtp_parameters_.encodings[i].max_bitrate_bps)) {
|
||||
new_bitrate = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bugs.webrtc.org/8807): The bitrate priority really doesn't require an
|
||||
// entire encoder reconfiguration, it just needs to update the bitrate
|
||||
// allocator.
|
||||
bool reconfigure_encoder = (new_parameters.encodings[0].max_bitrate_bps !=
|
||||
rtp_parameters_.encodings[0].max_bitrate_bps) ||
|
||||
(new_parameters.encodings[0].bitrate_priority !=
|
||||
rtp_parameters_.encodings[0].bitrate_priority);
|
||||
bool reconfigure_encoder =
|
||||
new_bitrate || (new_parameters.encodings[0].bitrate_priority !=
|
||||
rtp_parameters_.encodings[0].bitrate_priority);
|
||||
|
||||
// TODO(bugs.webrtc.org/8807): The active field as well should not require
|
||||
// a full encoder reconfiguration, but it needs to update both the bitrate
|
||||
// allocator and the video bitrate allocator.
|
||||
@ -1864,6 +1874,17 @@ WebRtcVideoChannel::WebRtcVideoSendStream::ValidateRtpParameters(
|
||||
"Attempted to set RtpParameters bitrate_priority to "
|
||||
"an invalid number. bitrate_priority must be > 0.");
|
||||
}
|
||||
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
||||
if (rtp_parameters.encodings[i].min_bitrate_bps &&
|
||||
rtp_parameters.encodings[i].max_bitrate_bps) {
|
||||
if (*rtp_parameters.encodings[i].max_bitrate_bps <
|
||||
*rtp_parameters.encodings[i].min_bitrate_bps) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
|
||||
"Attempted to set RtpParameters min bitrate "
|
||||
"larger than max bitrate.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
@ -1918,7 +1939,13 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
|
||||
}
|
||||
|
||||
int stream_max_bitrate = parameters_.max_bitrate_bps;
|
||||
if (rtp_parameters_.encodings[0].max_bitrate_bps) {
|
||||
// When simulcast is enabled (when there are multiple encodings),
|
||||
// encodings[i].max_bitrate_bps will be enforced by
|
||||
// encoder_config.simulcast_layers[i].max_bitrate_bps. Otherwise, it's
|
||||
// enforced by stream_max_bitrate, taking the minimum of the two maximums
|
||||
// (one coming from SDP, the other coming from RtpParameters).
|
||||
if (rtp_parameters_.encodings[0].max_bitrate_bps &&
|
||||
rtp_parameters_.encodings.size() == 1) {
|
||||
stream_max_bitrate =
|
||||
webrtc::MinPositive(*(rtp_parameters_.encodings[0].max_bitrate_bps),
|
||||
parameters_.max_bitrate_bps);
|
||||
@ -1939,7 +1966,7 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
|
||||
|
||||
// Application-controlled state is held in the encoder_config's
|
||||
// simulcast_layers. Currently this is used to control which simulcast layers
|
||||
// are active.
|
||||
// are active and for configuring the min/max bitrate.
|
||||
RTC_DCHECK_GE(rtp_parameters_.encodings.size(),
|
||||
encoder_config.number_of_streams);
|
||||
RTC_DCHECK_GT(encoder_config.number_of_streams, 0);
|
||||
@ -1947,6 +1974,14 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
|
||||
for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i) {
|
||||
encoder_config.simulcast_layers[i].active =
|
||||
rtp_parameters_.encodings[i].active;
|
||||
if (rtp_parameters_.encodings[i].min_bitrate_bps) {
|
||||
encoder_config.simulcast_layers[i].min_bitrate_bps =
|
||||
*rtp_parameters_.encodings[i].min_bitrate_bps;
|
||||
}
|
||||
if (rtp_parameters_.encodings[i].max_bitrate_bps) {
|
||||
encoder_config.simulcast_layers[i].max_bitrate_bps =
|
||||
*rtp_parameters_.encodings[i].max_bitrate_bps;
|
||||
}
|
||||
}
|
||||
|
||||
int max_qp = kDefaultQpMax;
|
||||
@ -2681,12 +2716,50 @@ std::vector<webrtc::VideoStream> EncoderStreamFactory::CreateEncoderStreams(
|
||||
(CodecNamesEq(codec_name_, kVp8CodecName) && is_screenshare_ &&
|
||||
screenshare_config_explicitly_enabled_)) {
|
||||
layers = GetSimulcastConfig(encoder_config.number_of_streams, width, height,
|
||||
encoder_config.max_bitrate_bps,
|
||||
encoder_config.bitrate_priority, max_qp_,
|
||||
max_framerate_, is_screenshare_);
|
||||
// Update the active simulcast layers.
|
||||
0 /*not used*/, encoder_config.bitrate_priority,
|
||||
max_qp_, max_framerate_, is_screenshare_);
|
||||
// Update the active simulcast layers and configured bitrates.
|
||||
bool is_highest_layer_max_bitrate_configured = false;
|
||||
for (size_t i = 0; i < layers.size(); ++i) {
|
||||
layers[i].active = encoder_config.simulcast_layers[i].active;
|
||||
// Update simulcast bitrates with configured min and max bitrate.
|
||||
if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) {
|
||||
layers[i].min_bitrate_bps =
|
||||
encoder_config.simulcast_layers[i].min_bitrate_bps;
|
||||
}
|
||||
if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) {
|
||||
layers[i].max_bitrate_bps =
|
||||
encoder_config.simulcast_layers[i].max_bitrate_bps;
|
||||
}
|
||||
if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0 &&
|
||||
encoder_config.simulcast_layers[i].max_bitrate_bps > 0) {
|
||||
// Min and max bitrate are configured.
|
||||
// Set target to 3/4 of the max bitrate (or to max if below min).
|
||||
layers[i].target_bitrate_bps = layers[i].max_bitrate_bps * 3 / 4;
|
||||
if (layers[i].target_bitrate_bps < layers[i].min_bitrate_bps)
|
||||
layers[i].target_bitrate_bps = layers[i].max_bitrate_bps;
|
||||
} else if (encoder_config.simulcast_layers[i].min_bitrate_bps > 0) {
|
||||
// Only min bitrate is configured, make sure target/max are above min.
|
||||
layers[i].target_bitrate_bps =
|
||||
std::max(layers[i].target_bitrate_bps, layers[i].min_bitrate_bps);
|
||||
layers[i].max_bitrate_bps =
|
||||
std::max(layers[i].max_bitrate_bps, layers[i].min_bitrate_bps);
|
||||
} else if (encoder_config.simulcast_layers[i].max_bitrate_bps > 0) {
|
||||
// Only max bitrate is configured, make sure min/target are below max.
|
||||
layers[i].min_bitrate_bps =
|
||||
std::min(layers[i].min_bitrate_bps, layers[i].max_bitrate_bps);
|
||||
layers[i].target_bitrate_bps =
|
||||
std::min(layers[i].target_bitrate_bps, layers[i].max_bitrate_bps);
|
||||
}
|
||||
if (i == layers.size() - 1) {
|
||||
is_highest_layer_max_bitrate_configured =
|
||||
encoder_config.simulcast_layers[i].max_bitrate_bps > 0;
|
||||
}
|
||||
}
|
||||
if (!is_screenshare_ && !is_highest_layer_max_bitrate_configured) {
|
||||
// No application-configured maximum for the largest layer.
|
||||
// If there is bitrate leftover, give it to the largest layer.
|
||||
BoostMaxSimulcastLayer(encoder_config.max_bitrate_bps, &layers);
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
@ -2212,6 +2212,21 @@ class WebRtcVideoChannelTest : public WebRtcVideoEngineTest {
|
||||
EXPECT_EQ(expected_encoder_bitrate, GetMaxEncoderBitrate());
|
||||
}
|
||||
|
||||
// Values from kSimulcastConfigs in simulcast.cc.
|
||||
const std::vector<webrtc::VideoStream> GetSimulcastBitrates720p() const {
|
||||
std::vector<webrtc::VideoStream> layers(3);
|
||||
layers[0].min_bitrate_bps = 30000;
|
||||
layers[0].target_bitrate_bps = 150000;
|
||||
layers[0].max_bitrate_bps = 200000;
|
||||
layers[1].min_bitrate_bps = 150000;
|
||||
layers[1].target_bitrate_bps = 500000;
|
||||
layers[1].max_bitrate_bps = 700000;
|
||||
layers[2].min_bitrate_bps = 600000;
|
||||
layers[2].target_bitrate_bps = 2500000;
|
||||
layers[2].max_bitrate_bps = 2500000;
|
||||
return layers;
|
||||
}
|
||||
|
||||
std::unique_ptr<FakeCall> fake_call_;
|
||||
std::unique_ptr<VideoMediaChannel> channel_;
|
||||
cricket::VideoSendParameters send_parameters_;
|
||||
@ -3980,6 +3995,31 @@ TEST_F(WebRtcVideoChannelTest, SetMaxSendBandwidthAndAddSendStream) {
|
||||
stream->GetVideoStreams()[0].max_bitrate_bps);
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannelTest,
|
||||
MaxBitrateIsMinimumOfMaxSendBandwidthAndMaxEncodingBitrate) {
|
||||
send_parameters_.max_bandwidth_bps = 99999;
|
||||
FakeVideoSendStream* stream = AddSendStream();
|
||||
ExpectSetMaxBitrate(send_parameters_.max_bandwidth_bps);
|
||||
ASSERT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
ASSERT_EQ(1u, stream->GetVideoStreams().size());
|
||||
EXPECT_EQ(send_parameters_.max_bandwidth_bps,
|
||||
stream->GetVideoStreams()[0].max_bitrate_bps);
|
||||
|
||||
// Get and set the rtp encoding parameters.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(1u, parameters.encodings.size());
|
||||
|
||||
parameters.encodings[0].max_bitrate_bps = 99999 - 1;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
EXPECT_EQ(parameters.encodings[0].max_bitrate_bps,
|
||||
stream->GetVideoStreams()[0].max_bitrate_bps);
|
||||
|
||||
parameters.encodings[0].max_bitrate_bps = 99999 + 1;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
EXPECT_EQ(send_parameters_.max_bandwidth_bps,
|
||||
stream->GetVideoStreams()[0].max_bitrate_bps);
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannelTest, SetMaxSendBitrateCanIncreaseSenderBitrate) {
|
||||
cricket::VideoSendParameters parameters;
|
||||
parameters.codecs.push_back(GetEngineCodec("VP8"));
|
||||
@ -5371,6 +5411,325 @@ TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersPrioritySimulcastStreams) {
|
||||
EXPECT_TRUE(channel_->SetVideoSend(primary_ssrc, nullptr, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannelTest, GetAndSetRtpSendParametersMinAndMaxBitrate) {
|
||||
const size_t kNumSimulcastStreams = 3;
|
||||
SetUpSimulcast(true, false);
|
||||
|
||||
// Get and set the rtp encoding parameters.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
for (const auto& encoding : parameters.encodings) {
|
||||
EXPECT_FALSE(encoding.min_bitrate_bps);
|
||||
EXPECT_FALSE(encoding.max_bitrate_bps);
|
||||
}
|
||||
|
||||
// Change the value and set it on the VideoChannel.
|
||||
parameters.encodings[0].min_bitrate_bps = 100000;
|
||||
parameters.encodings[0].max_bitrate_bps = 200000;
|
||||
parameters.encodings[1].min_bitrate_bps = 300000;
|
||||
parameters.encodings[1].max_bitrate_bps = 400000;
|
||||
parameters.encodings[2].min_bitrate_bps = 500000;
|
||||
parameters.encodings[2].max_bitrate_bps = 600000;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
|
||||
// Verify that the bitrates are set on the VideoChannel.
|
||||
parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
EXPECT_EQ(100000, parameters.encodings[0].min_bitrate_bps);
|
||||
EXPECT_EQ(200000, parameters.encodings[0].max_bitrate_bps);
|
||||
EXPECT_EQ(300000, parameters.encodings[1].min_bitrate_bps);
|
||||
EXPECT_EQ(400000, parameters.encodings[1].max_bitrate_bps);
|
||||
EXPECT_EQ(500000, parameters.encodings[2].min_bitrate_bps);
|
||||
EXPECT_EQ(600000, parameters.encodings[2].max_bitrate_bps);
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersFailsWithIncorrectBitrate) {
|
||||
const size_t kNumSimulcastStreams = 3;
|
||||
SetUpSimulcast(true, false);
|
||||
|
||||
// Get and set the rtp encoding parameters.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
|
||||
// Max bitrate lower than min bitrate should fail.
|
||||
parameters.encodings[2].min_bitrate_bps = 100000;
|
||||
parameters.encodings[2].max_bitrate_bps = 100000 - 1;
|
||||
EXPECT_EQ(webrtc::RTCErrorType::INVALID_RANGE,
|
||||
channel_->SetRtpSendParameters(last_ssrc_, parameters).type());
|
||||
}
|
||||
|
||||
// Test that min and max bitrate values set via RtpParameters are correctly
|
||||
// propagated to the underlying encoder, and that the target is set to 3/4 of
|
||||
// the maximum (3/4 was chosen because it's similar to the simulcast defaults
|
||||
// that are used if no min/max are specified).
|
||||
TEST_F(WebRtcVideoChannelTest, MinAndMaxSimulcastBitratePropagatedToEncoder) {
|
||||
const size_t kNumSimulcastStreams = 3;
|
||||
FakeVideoSendStream* stream = SetUpSimulcast(true, false);
|
||||
|
||||
// Send a full size frame so all simulcast layers are used when reconfiguring.
|
||||
FakeVideoCapturerWithTaskQueue capturer;
|
||||
VideoOptions options;
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, &options, &capturer));
|
||||
EXPECT_EQ(cricket::CS_RUNNING,
|
||||
capturer.Start(capturer.GetSupportedFormats()->front()));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(capturer.CaptureFrame());
|
||||
|
||||
// Get and set the rtp encoding parameters.
|
||||
// Change the value and set it on the VideoChannel.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
parameters.encodings[0].min_bitrate_bps = 100000;
|
||||
parameters.encodings[0].max_bitrate_bps = 200000;
|
||||
parameters.encodings[1].min_bitrate_bps = 300000;
|
||||
parameters.encodings[1].max_bitrate_bps = 400000;
|
||||
parameters.encodings[2].min_bitrate_bps = 500000;
|
||||
parameters.encodings[2].max_bitrate_bps = 600000;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
|
||||
// Verify that the new value propagated down to the encoder.
|
||||
// Check that WebRtcVideoSendStream updates VideoEncoderConfig correctly.
|
||||
EXPECT_EQ(2, stream->num_encoder_reconfigurations());
|
||||
webrtc::VideoEncoderConfig encoder_config = stream->GetEncoderConfig().Copy();
|
||||
EXPECT_EQ(kNumSimulcastStreams, encoder_config.number_of_streams);
|
||||
EXPECT_EQ(kNumSimulcastStreams, encoder_config.simulcast_layers.size());
|
||||
EXPECT_EQ(100000, encoder_config.simulcast_layers[0].min_bitrate_bps);
|
||||
EXPECT_EQ(200000, encoder_config.simulcast_layers[0].max_bitrate_bps);
|
||||
EXPECT_EQ(300000, encoder_config.simulcast_layers[1].min_bitrate_bps);
|
||||
EXPECT_EQ(400000, encoder_config.simulcast_layers[1].max_bitrate_bps);
|
||||
EXPECT_EQ(500000, encoder_config.simulcast_layers[2].min_bitrate_bps);
|
||||
EXPECT_EQ(600000, encoder_config.simulcast_layers[2].max_bitrate_bps);
|
||||
|
||||
// FakeVideoSendStream calls CreateEncoderStreams, test that the vector of
|
||||
// VideoStreams are created appropriately for the simulcast case.
|
||||
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
|
||||
// Target bitrate: 200000 * 3 / 4 = 150000.
|
||||
EXPECT_EQ(100000, stream->GetVideoStreams()[0].min_bitrate_bps);
|
||||
EXPECT_EQ(150000, stream->GetVideoStreams()[0].target_bitrate_bps);
|
||||
EXPECT_EQ(200000, stream->GetVideoStreams()[0].max_bitrate_bps);
|
||||
// Target bitrate: 400000 * 3 / 4 = 300000.
|
||||
EXPECT_EQ(300000, stream->GetVideoStreams()[1].min_bitrate_bps);
|
||||
EXPECT_EQ(300000, stream->GetVideoStreams()[1].target_bitrate_bps);
|
||||
EXPECT_EQ(400000, stream->GetVideoStreams()[1].max_bitrate_bps);
|
||||
// Target bitrate: 600000 * 3 / 4 = 450000, less than min -> max.
|
||||
EXPECT_EQ(500000, stream->GetVideoStreams()[2].min_bitrate_bps);
|
||||
EXPECT_EQ(600000, stream->GetVideoStreams()[2].target_bitrate_bps);
|
||||
EXPECT_EQ(600000, stream->GetVideoStreams()[2].max_bitrate_bps);
|
||||
|
||||
// No parameter changed, encoder should not be reconfigured.
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
EXPECT_EQ(2, stream->num_encoder_reconfigurations());
|
||||
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, nullptr, nullptr));
|
||||
}
|
||||
|
||||
// Test to only specify the min or max bitrate value for a layer via
|
||||
// RtpParameters. The unspecified min/max and target value should be set to the
|
||||
// simulcast default that is used if no min/max are specified.
|
||||
TEST_F(WebRtcVideoChannelTest, MinOrMaxSimulcastBitratePropagatedToEncoder) {
|
||||
const size_t kNumSimulcastStreams = 3;
|
||||
const std::vector<webrtc::VideoStream> kDefault = GetSimulcastBitrates720p();
|
||||
FakeVideoSendStream* stream = SetUpSimulcast(true, false);
|
||||
|
||||
// Send a full size frame so all simulcast layers are used when reconfiguring.
|
||||
FakeVideoCapturerWithTaskQueue capturer;
|
||||
VideoOptions options;
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, &options, &capturer));
|
||||
EXPECT_EQ(cricket::CS_RUNNING,
|
||||
capturer.Start(capturer.GetSupportedFormats()->front()));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(capturer.CaptureFrame());
|
||||
|
||||
// Get and set the rtp encoding parameters.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
|
||||
// Change the value and set it on the VideoChannel.
|
||||
// Layer 0: only configure min bitrate.
|
||||
const int kMinBpsLayer0 = kDefault[0].min_bitrate_bps + 1;
|
||||
parameters.encodings[0].min_bitrate_bps = kMinBpsLayer0;
|
||||
// Layer 1: only configure max bitrate.
|
||||
const int kMaxBpsLayer1 = kDefault[1].max_bitrate_bps - 1;
|
||||
parameters.encodings[1].max_bitrate_bps = kMaxBpsLayer1;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
|
||||
// Verify that the new value propagated down to the encoder.
|
||||
// Check that WebRtcVideoSendStream updates VideoEncoderConfig correctly.
|
||||
webrtc::VideoEncoderConfig encoder_config = stream->GetEncoderConfig().Copy();
|
||||
EXPECT_EQ(kNumSimulcastStreams, encoder_config.number_of_streams);
|
||||
EXPECT_EQ(kNumSimulcastStreams, encoder_config.simulcast_layers.size());
|
||||
EXPECT_EQ(kMinBpsLayer0, encoder_config.simulcast_layers[0].min_bitrate_bps);
|
||||
EXPECT_EQ(-1, encoder_config.simulcast_layers[0].max_bitrate_bps);
|
||||
EXPECT_EQ(-1, encoder_config.simulcast_layers[1].min_bitrate_bps);
|
||||
EXPECT_EQ(kMaxBpsLayer1, encoder_config.simulcast_layers[1].max_bitrate_bps);
|
||||
EXPECT_EQ(-1, encoder_config.simulcast_layers[2].min_bitrate_bps);
|
||||
EXPECT_EQ(-1, encoder_config.simulcast_layers[2].max_bitrate_bps);
|
||||
|
||||
// FakeVideoSendStream calls CreateEncoderStreams, test that the vector of
|
||||
// VideoStreams are created appropriately for the simulcast case.
|
||||
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
|
||||
// Layer 0: min configured bitrate should overwrite min default.
|
||||
EXPECT_EQ(kMinBpsLayer0, stream->GetVideoStreams()[0].min_bitrate_bps);
|
||||
EXPECT_EQ(kDefault[0].target_bitrate_bps,
|
||||
stream->GetVideoStreams()[0].target_bitrate_bps);
|
||||
EXPECT_EQ(kDefault[0].max_bitrate_bps,
|
||||
stream->GetVideoStreams()[0].max_bitrate_bps);
|
||||
// Layer 1: max configured bitrate should overwrite max default.
|
||||
EXPECT_EQ(kDefault[1].min_bitrate_bps,
|
||||
stream->GetVideoStreams()[1].min_bitrate_bps);
|
||||
EXPECT_EQ(kDefault[1].target_bitrate_bps,
|
||||
stream->GetVideoStreams()[1].target_bitrate_bps);
|
||||
EXPECT_EQ(kMaxBpsLayer1, stream->GetVideoStreams()[1].max_bitrate_bps);
|
||||
// Layer 2: min and max bitrate not configured, default expected.
|
||||
EXPECT_EQ(kDefault[2].min_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].min_bitrate_bps);
|
||||
EXPECT_EQ(kDefault[2].target_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].target_bitrate_bps);
|
||||
EXPECT_EQ(kDefault[2].max_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].max_bitrate_bps);
|
||||
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, nullptr, nullptr));
|
||||
}
|
||||
|
||||
// Test that specifying the min (or max) bitrate value for a layer via
|
||||
// RtpParameters above (or below) the simulcast default max (or min) adjusts the
|
||||
// unspecified values accordingly.
|
||||
TEST_F(WebRtcVideoChannelTest, SetMinAndMaxSimulcastBitrateAboveBelowDefault) {
|
||||
const size_t kNumSimulcastStreams = 3;
|
||||
const std::vector<webrtc::VideoStream> kDefault = GetSimulcastBitrates720p();
|
||||
FakeVideoSendStream* stream = SetUpSimulcast(true, false);
|
||||
|
||||
// Send a full size frame so all simulcast layers are used when reconfiguring.
|
||||
FakeVideoCapturerWithTaskQueue capturer;
|
||||
VideoOptions options;
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, &options, &capturer));
|
||||
EXPECT_EQ(cricket::CS_RUNNING,
|
||||
capturer.Start(capturer.GetSupportedFormats()->front()));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(capturer.CaptureFrame());
|
||||
|
||||
// Get and set the rtp encoding parameters.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
|
||||
// Change the value and set it on the VideoChannel.
|
||||
// For layer 0, set the min bitrate above the default max.
|
||||
const int kMinBpsLayer0 = kDefault[0].max_bitrate_bps + 1;
|
||||
parameters.encodings[0].min_bitrate_bps = kMinBpsLayer0;
|
||||
// For layer 1, set the max bitrate below the default min.
|
||||
const int kMaxBpsLayer1 = kDefault[1].min_bitrate_bps - 1;
|
||||
parameters.encodings[1].max_bitrate_bps = kMaxBpsLayer1;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
|
||||
// Verify that the new value propagated down to the encoder.
|
||||
// FakeVideoSendStream calls CreateEncoderStreams, test that the vector of
|
||||
// VideoStreams are created appropriately for the simulcast case.
|
||||
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
|
||||
// Layer 0: Min bitrate above default max (target/max should be adjusted).
|
||||
EXPECT_EQ(kMinBpsLayer0, stream->GetVideoStreams()[0].min_bitrate_bps);
|
||||
EXPECT_EQ(kMinBpsLayer0, stream->GetVideoStreams()[0].target_bitrate_bps);
|
||||
EXPECT_EQ(kMinBpsLayer0, stream->GetVideoStreams()[0].max_bitrate_bps);
|
||||
// Layer 1: Max bitrate below default min (min/target should be adjusted).
|
||||
EXPECT_EQ(kMaxBpsLayer1, stream->GetVideoStreams()[1].min_bitrate_bps);
|
||||
EXPECT_EQ(kMaxBpsLayer1, stream->GetVideoStreams()[1].target_bitrate_bps);
|
||||
EXPECT_EQ(kMaxBpsLayer1, stream->GetVideoStreams()[1].max_bitrate_bps);
|
||||
// Layer 2: min and max bitrate not configured, default expected.
|
||||
EXPECT_EQ(kDefault[2].min_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].min_bitrate_bps);
|
||||
EXPECT_EQ(kDefault[2].target_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].target_bitrate_bps);
|
||||
EXPECT_EQ(kDefault[2].max_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].max_bitrate_bps);
|
||||
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, nullptr, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannelTest, BandwidthAboveTotalMaxBitrateGivenToMaxLayer) {
|
||||
const size_t kNumSimulcastStreams = 3;
|
||||
const std::vector<webrtc::VideoStream> kDefault = GetSimulcastBitrates720p();
|
||||
FakeVideoSendStream* stream = SetUpSimulcast(true, false);
|
||||
|
||||
// Send a full size frame so all simulcast layers are used when reconfiguring.
|
||||
FakeVideoCapturerWithTaskQueue capturer;
|
||||
VideoOptions options;
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, &options, &capturer));
|
||||
EXPECT_EQ(cricket::CS_RUNNING,
|
||||
capturer.Start(capturer.GetSupportedFormats()->front()));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(capturer.CaptureFrame());
|
||||
|
||||
// Set max bitrate for all but the highest layer.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
parameters.encodings[0].max_bitrate_bps = kDefault[0].max_bitrate_bps;
|
||||
parameters.encodings[1].max_bitrate_bps = kDefault[1].max_bitrate_bps;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
|
||||
// Set max bandwidth equal to total max bitrate.
|
||||
send_parameters_.max_bandwidth_bps =
|
||||
GetTotalMaxBitrateBps(stream->GetVideoStreams());
|
||||
ExpectSetMaxBitrate(send_parameters_.max_bandwidth_bps);
|
||||
ASSERT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
|
||||
// No bitrate above the total max to give to the highest layer.
|
||||
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
|
||||
EXPECT_EQ(kDefault[2].max_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].max_bitrate_bps);
|
||||
|
||||
// Set max bandwidth above the total max bitrate.
|
||||
send_parameters_.max_bandwidth_bps =
|
||||
GetTotalMaxBitrateBps(stream->GetVideoStreams()) + 1;
|
||||
ExpectSetMaxBitrate(send_parameters_.max_bandwidth_bps);
|
||||
ASSERT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
|
||||
// The highest layer has no max bitrate set -> the bitrate above the total
|
||||
// max should be given to the highest layer.
|
||||
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
|
||||
EXPECT_EQ(send_parameters_.max_bandwidth_bps,
|
||||
GetTotalMaxBitrateBps(stream->GetVideoStreams()));
|
||||
EXPECT_EQ(kDefault[2].max_bitrate_bps + 1,
|
||||
stream->GetVideoStreams()[2].max_bitrate_bps);
|
||||
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, nullptr, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannelTest,
|
||||
BandwidthAboveTotalMaxBitrateNotGivenToMaxLayerIfMaxBitrateSet) {
|
||||
const size_t kNumSimulcastStreams = 3;
|
||||
const std::vector<webrtc::VideoStream> kDefault = GetSimulcastBitrates720p();
|
||||
EXPECT_EQ(kNumSimulcastStreams, kDefault.size());
|
||||
FakeVideoSendStream* stream = SetUpSimulcast(true, false);
|
||||
|
||||
// Send a full size frame so all simulcast layers are used when reconfiguring.
|
||||
FakeVideoCapturerWithTaskQueue capturer;
|
||||
VideoOptions options;
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, &options, &capturer));
|
||||
EXPECT_EQ(cricket::CS_RUNNING,
|
||||
capturer.Start(capturer.GetSupportedFormats()->front()));
|
||||
channel_->SetSend(true);
|
||||
EXPECT_TRUE(capturer.CaptureFrame());
|
||||
|
||||
// Set max bitrate for the highest layer.
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(last_ssrc_);
|
||||
EXPECT_EQ(kNumSimulcastStreams, parameters.encodings.size());
|
||||
parameters.encodings[2].max_bitrate_bps = kDefault[2].max_bitrate_bps;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(last_ssrc_, parameters).ok());
|
||||
|
||||
// Set max bandwidth above the total max bitrate.
|
||||
send_parameters_.max_bandwidth_bps =
|
||||
GetTotalMaxBitrateBps(stream->GetVideoStreams()) + 1;
|
||||
ExpectSetMaxBitrate(send_parameters_.max_bandwidth_bps);
|
||||
ASSERT_TRUE(channel_->SetSendParameters(send_parameters_));
|
||||
|
||||
// The highest layer has the max bitrate set -> the bitrate above the total
|
||||
// max should not be given to the highest layer.
|
||||
EXPECT_EQ(kNumSimulcastStreams, stream->GetVideoStreams().size());
|
||||
EXPECT_EQ(*parameters.encodings[2].max_bitrate_bps,
|
||||
stream->GetVideoStreams()[2].max_bitrate_bps);
|
||||
|
||||
EXPECT_TRUE(channel_->SetVideoSend(last_ssrc_, nullptr, nullptr));
|
||||
}
|
||||
|
||||
// Test that a stream will not be sending if its encoding is made inactive
|
||||
// through SetRtpSendParameters.
|
||||
TEST_F(WebRtcVideoChannelTest, SetRtpSendParametersOneEncodingActive) {
|
||||
|
@ -58,8 +58,7 @@ bool UnimplementedRtpEncodingParameterHasValue(
|
||||
// layer.
|
||||
bool PerSenderRtpEncodingParameterHasValue(
|
||||
const RtpEncodingParameters& encoding_params) {
|
||||
if (encoding_params.max_bitrate_bps.has_value() ||
|
||||
encoding_params.bitrate_priority != kDefaultBitratePriority) {
|
||||
if (encoding_params.bitrate_priority != kDefaultBitratePriority) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -959,31 +959,31 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCantSetPerSenderEncodingParameters) {
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
|
||||
params.encodings[1].max_bitrate_bps = 200000;
|
||||
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
video_rtp_sender_->SetParameters(params).type());
|
||||
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, SetVideoMaxSendBitrate) {
|
||||
TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrate) {
|
||||
CreateVideoRtpSender();
|
||||
|
||||
EXPECT_EQ(-1, video_media_channel_->max_bps());
|
||||
webrtc::RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_EQ(1, params.encodings.size());
|
||||
EXPECT_FALSE(params.encodings[0].min_bitrate_bps);
|
||||
EXPECT_FALSE(params.encodings[0].max_bitrate_bps);
|
||||
params.encodings[0].min_bitrate_bps = 100;
|
||||
params.encodings[0].max_bitrate_bps = 1000;
|
||||
EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok());
|
||||
|
||||
// Read back the parameters and verify they have been changed.
|
||||
params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_EQ(1, params.encodings.size());
|
||||
EXPECT_EQ(100, params.encodings[0].min_bitrate_bps);
|
||||
EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
|
||||
|
||||
// Verify that the video channel received the new parameters.
|
||||
params = video_media_channel_->GetRtpSendParameters(kVideoSsrc);
|
||||
EXPECT_EQ(1, params.encodings.size());
|
||||
EXPECT_EQ(100, params.encodings[0].min_bitrate_bps);
|
||||
EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
|
||||
|
||||
// Verify that the global bitrate limit has not been changed.
|
||||
@ -992,6 +992,34 @@ TEST_F(RtpSenderReceiverTest, SetVideoMaxSendBitrate) {
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrateSimulcast) {
|
||||
// Add a simulcast specific send stream that contains 2 encoding parameters.
|
||||
std::vector<uint32_t> ssrcs({1, 2});
|
||||
cricket::StreamParams stream_params =
|
||||
cricket::CreateSimStreamParams("cname", ssrcs);
|
||||
video_media_channel_->AddSendStream(stream_params);
|
||||
uint32_t primary_ssrc = stream_params.first_ssrc();
|
||||
CreateVideoRtpSender(primary_ssrc);
|
||||
|
||||
RtpParameters params = video_rtp_sender_->GetParameters();
|
||||
EXPECT_EQ(ssrcs.size(), params.encodings.size());
|
||||
params.encodings[0].min_bitrate_bps = 100;
|
||||
params.encodings[0].max_bitrate_bps = 1000;
|
||||
params.encodings[1].min_bitrate_bps = 200;
|
||||
params.encodings[1].max_bitrate_bps = 2000;
|
||||
EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok());
|
||||
|
||||
// Verify that the video channel received the new parameters.
|
||||
params = video_media_channel_->GetRtpSendParameters(primary_ssrc);
|
||||
EXPECT_EQ(ssrcs.size(), params.encodings.size());
|
||||
EXPECT_EQ(100, params.encodings[0].min_bitrate_bps);
|
||||
EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps);
|
||||
EXPECT_EQ(200, params.encodings[1].min_bitrate_bps);
|
||||
EXPECT_EQ(2000, params.encodings[1].max_bitrate_bps);
|
||||
|
||||
DestroyVideoRtpSender();
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderReceiverTest, SetVideoBitratePriority) {
|
||||
CreateVideoRtpSender();
|
||||
|
||||
|
Reference in New Issue
Block a user