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}
diff --git a/api/rtpparameters.h b/api/rtpparameters.h
index 0725ec7..e2405d3 100644
--- a/api/rtpparameters.h
+++ b/api/rtpparameters.h
@@ -401,14 +401,6 @@
   // 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 @@
   // 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.
diff --git a/api/rtpsenderinterface.h b/api/rtpsenderinterface.h
index e933614..66267c7 100644
--- a/api/rtpsenderinterface.h
+++ b/api/rtpsenderinterface.h
@@ -57,6 +57,7 @@
   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.
diff --git a/media/engine/simulcast.cc b/media/engine/simulcast.cc
index ffc7971..607d141 100644
--- a/media/engine/simulcast.cc
+++ b/media/engine/simulcast.cc
@@ -151,6 +151,9 @@
 
 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 @@
 }
 
 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 @@
 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 @@
     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 @@
       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 @@
     size_t max_layers,
     int width,
     int height,
-    int max_bitrate_bps,
     double bitrate_priority,
     int max_qp,
     int max_framerate,
diff --git a/media/engine/simulcast.h b/media/engine/simulcast.h
index 7a98809..3172f5e 100644
--- a/media/engine/simulcast.h
+++ b/media/engine/simulcast.h
@@ -21,35 +21,39 @@
 // 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,
diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc
index 7c3ecd1..26bb83d 100644
--- a/media/engine/webrtcvideoengine.cc
+++ b/media/engine/webrtcvideoengine.cc
@@ -1800,13 +1800,23 @@
     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 @@
                          "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 @@
   }
 
   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 @@
 
   // 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 @@
   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 @@
       (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;
   }
diff --git a/media/engine/webrtcvideoengine_unittest.cc b/media/engine/webrtcvideoengine_unittest.cc
index 5248979..2b048fc 100644
--- a/media/engine/webrtcvideoengine_unittest.cc
+++ b/media/engine/webrtcvideoengine_unittest.cc
@@ -2212,6 +2212,21 @@
     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 @@
             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 @@
   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) {
diff --git a/pc/rtpsender.cc b/pc/rtpsender.cc
index cffcd8b..e8105a8 100644
--- a/pc/rtpsender.cc
+++ b/pc/rtpsender.cc
@@ -58,8 +58,7 @@
 // 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;
diff --git a/pc/rtpsenderreceiver_unittest.cc b/pc/rtpsenderreceiver_unittest.cc
index 99e624d..8151ad6 100644
--- a/pc/rtpsenderreceiver_unittest.cc
+++ b/pc/rtpsenderreceiver_unittest.cc
@@ -959,31 +959,31 @@
             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 @@
   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();