Implement new specification for degradation preference

The degradation preference is now based on the content hint of the track
if it's unspecified.

Bug: webrtc:11164
Change-Id: Iaa0dbf1c1bf68a46fc5131e534d423c30c5439c7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161233
Commit-Queue: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30691}
diff --git a/api/rtp_parameters.h b/api/rtp_parameters.h
index 358a582..a22f764 100644
--- a/api/rtp_parameters.h
+++ b/api/rtp_parameters.h
@@ -609,8 +609,7 @@
   // When bandwidth is constrained and the RtpSender needs to choose between
   // degrading resolution or degrading framerate, degradationPreference
   // indicates which is preferred. Only for video tracks.
-  DegradationPreference degradation_preference =
-      DegradationPreference::BALANCED;
+  absl::optional<DegradationPreference> degradation_preference;
 
   bool operator==(const RtpParameters& o) const {
     return mid == o.mid && codecs == o.codecs &&
diff --git a/media/BUILD.gn b/media/BUILD.gn
index f68f991..8c2d8c0 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -280,6 +280,7 @@
     "..:webrtc_common",
     "../api:call_api",
     "../api:libjingle_peerconnection_api",
+    "../api:media_stream_interface",
     "../api:rtp_parameters",
     "../api:scoped_refptr",
     "../api:transport_api",
diff --git a/media/base/media_channel.cc b/media/base/media_channel.cc
index 3417924..2e9bfc3 100644
--- a/media/base/media_channel.cc
+++ b/media/base/media_channel.cc
@@ -12,7 +12,8 @@
 
 namespace cricket {
 
-VideoOptions::VideoOptions() = default;
+VideoOptions::VideoOptions()
+    : content_hint(webrtc::VideoTrackInterface::ContentHint::kNone) {}
 VideoOptions::~VideoOptions() = default;
 
 MediaChannel::MediaChannel(const MediaConfig& config)
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index 8ee4a23..a62c618 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -23,6 +23,7 @@
 #include "api/crypto/frame_decryptor_interface.h"
 #include "api/crypto/frame_encryptor_interface.h"
 #include "api/frame_transformer_interface.h"
+#include "api/media_stream_interface.h"
 #include "api/rtc_error.h"
 #include "api/rtp_parameters.h"
 #include "api/transport/media/media_transport_config.h"
@@ -144,6 +145,7 @@
   // things, e.g., screencast of a text document and screencast of a
   // youtube video have different needs.
   absl::optional<bool> is_screencast;
+  webrtc::VideoTrackInterface::ContentHint content_hint;
 
  private:
   template <typename T>
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index b2f8429..48aea63 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -19,6 +19,7 @@
 
 #include "absl/algorithm/container.h"
 #include "absl/strings/match.h"
+#include "api/media_stream_interface.h"
 #include "api/transport/datagram_transport_interface.h"
 #include "api/units/data_rate.h"
 #include "api/video/video_codec_constants.h"
@@ -1948,25 +1949,37 @@
   // result in blurry and unreadable text.
   // |this| acts like a VideoSource to make sure SinkWants are handled on the
   // correct thread.
-  webrtc::DegradationPreference degradation_preference;
-  if (rtp_parameters_.degradation_preference !=
-      webrtc::DegradationPreference::BALANCED) {
-    // If the degradationPreference is different from the default value, assume
-    // it is what we want, regardless of trials or other internal settings.
-    degradation_preference = rtp_parameters_.degradation_preference;
-  } else if (!enable_cpu_overuse_detection_) {
-    degradation_preference = webrtc::DegradationPreference::DISABLED;
-  } else if (parameters_.options.is_screencast.value_or(false)) {
-    degradation_preference = webrtc::DegradationPreference::MAINTAIN_RESOLUTION;
-  } else if (webrtc::field_trial::IsEnabled(
-                 "WebRTC-Video-BalancedDegradation")) {
-    degradation_preference = webrtc::DegradationPreference::BALANCED;
-  } else {
-    // TODO(orphis): The default should be BALANCED as the standard mandates.
-    // Right now, there is no way to set it to BALANCED as it would change
-    // the behavior for any project expecting MAINTAIN_FRAMERATE by default.
-    degradation_preference = webrtc::DegradationPreference::MAINTAIN_FRAMERATE;
+  if (!enable_cpu_overuse_detection_) {
+    return webrtc::DegradationPreference::DISABLED;
   }
+
+  webrtc::DegradationPreference degradation_preference;
+  if (rtp_parameters_.degradation_preference.has_value()) {
+    degradation_preference = *rtp_parameters_.degradation_preference;
+  } else {
+    if (parameters_.options.content_hint ==
+        webrtc::VideoTrackInterface::ContentHint::kFluid) {
+      degradation_preference =
+          webrtc::DegradationPreference::MAINTAIN_FRAMERATE;
+    } else if (parameters_.options.is_screencast.value_or(false) ||
+               parameters_.options.content_hint ==
+                   webrtc::VideoTrackInterface::ContentHint::kDetailed ||
+               parameters_.options.content_hint ==
+                   webrtc::VideoTrackInterface::ContentHint::kText) {
+      degradation_preference =
+          webrtc::DegradationPreference::MAINTAIN_RESOLUTION;
+    } else if (webrtc::field_trial::IsEnabled(
+                   "WebRTC-Video-BalancedDegradation")) {
+      // Standard wants balanced by default, but it needs to be tuned first.
+      degradation_preference = webrtc::DegradationPreference::BALANCED;
+    } else {
+      // Keep MAINTAIN_FRAMERATE by default until BALANCED has been tuned for
+      // all codecs and launched.
+      degradation_preference =
+          webrtc::DegradationPreference::MAINTAIN_FRAMERATE;
+    }
+  }
+
   return degradation_preference;
 }
 
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index d294d31..d33a2c3 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -7318,8 +7318,7 @@
 
   webrtc::RtpParameters rtp_parameters =
       channel_->GetRtpSendParameters(last_ssrc_);
-  EXPECT_EQ(rtp_parameters.degradation_preference,
-            webrtc::DegradationPreference::BALANCED);
+  EXPECT_FALSE(rtp_parameters.degradation_preference.has_value());
   rtp_parameters.degradation_preference =
       webrtc::DegradationPreference::MAINTAIN_FRAMERATE;
 
diff --git a/pc/rtp_sender.cc b/pc/rtp_sender.cc
index 5a955e3..c56f4a9 100644
--- a/pc/rtp_sender.cc
+++ b/pc/rtp_sender.cc
@@ -606,6 +606,7 @@
     options.is_screencast = source->is_screencast();
     options.video_noise_reduction = source->needs_denoising();
   }
+  options.content_hint = cached_track_content_hint_;
   switch (cached_track_content_hint_) {
     case VideoTrackInterface::ContentHint::kNone:
       break;
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/RtpSenderTest.java b/sdk/android/instrumentationtests/src/org/webrtc/RtpSenderTest.java
index 14d76d0..af9c62b 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/RtpSenderTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/RtpSenderTest.java
@@ -12,6 +12,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
@@ -54,7 +55,7 @@
 
     RtpParameters parameters = sender.getParameters();
     assertNotNull(parameters);
-    assertEquals(DegradationPreference.BALANCED, parameters.degradationPreference);
+    assertNull(parameters.degradationPreference);
 
     parameters.degradationPreference = DegradationPreference.MAINTAIN_FRAMERATE;
     assertTrue(sender.setParameters(parameters));
diff --git a/sdk/android/src/jni/pc/rtp_parameters.cc b/sdk/android/src/jni/pc/rtp_parameters.cc
index 4bed3f8..5b394ab 100644
--- a/sdk/android/src/jni/pc/rtp_parameters.cc
+++ b/sdk/android/src/jni/pc/rtp_parameters.cc
@@ -187,8 +187,10 @@
     const RtpParameters& parameters) {
   return Java_RtpParameters_Constructor(
       env, NativeToJavaString(env, parameters.transaction_id),
-      Java_DegradationPreference_fromNativeIndex(
-          env, static_cast<int>(parameters.degradation_preference)),
+      parameters.degradation_preference.has_value()
+          ? Java_DegradationPreference_fromNativeIndex(
+                env, static_cast<int>(*parameters.degradation_preference))
+          : nullptr,
       NativeToJavaRtpRtcpParameters(env, parameters.rtcp),
       NativeToJavaList(env, parameters.header_extensions,
                        &NativeToJavaRtpHeaderExtensionParameter),
diff --git a/sdk/objc/api/peerconnection/RTCRtpParameters.mm b/sdk/objc/api/peerconnection/RTCRtpParameters.mm
index d70f7da..cbb4576 100644
--- a/sdk/objc/api/peerconnection/RTCRtpParameters.mm
+++ b/sdk/objc/api/peerconnection/RTCRtpParameters.mm
@@ -56,9 +56,9 @@
     }
     _codecs = codecs;
 
-    _degradationPreference = @([RTCRtpParameters
+    _degradationPreference = [RTCRtpParameters
         degradationPreferenceFromNativeDegradationPreference:nativeParameters
-                                                                 .degradation_preference]);
+                                                                 .degradation_preference];
   }
   return self;
 }
@@ -98,17 +98,21 @@
   }
 }
 
-+ (RTCDegradationPreference)degradationPreferenceFromNativeDegradationPreference:
-    (webrtc::DegradationPreference)nativeDegradationPreference {
-  switch (nativeDegradationPreference) {
++ (NSNumber *)degradationPreferenceFromNativeDegradationPreference:
+    (absl::optional<webrtc::DegradationPreference>)nativeDegradationPreference {
+  if (!nativeDegradationPreference.has_value()) {
+    return nil;
+  }
+
+  switch (*nativeDegradationPreference) {
     case webrtc::DegradationPreference::DISABLED:
-      return RTCDegradationPreferenceDisabled;
+      return @(RTCDegradationPreferenceDisabled);
     case webrtc::DegradationPreference::MAINTAIN_FRAMERATE:
-      return RTCDegradationPreferenceMaintainFramerate;
+      return @(RTCDegradationPreferenceMaintainFramerate);
     case webrtc::DegradationPreference::MAINTAIN_RESOLUTION:
-      return RTCDegradationPreferenceMaintainResolution;
+      return @(RTCDegradationPreferenceMaintainResolution);
     case webrtc::DegradationPreference::BALANCED:
-      return RTCDegradationPreferenceBalanced;
+      return @(RTCDegradationPreferenceBalanced);
   }
 }