Add support for DegradationPreference in Android SDK

This wires the current degradation preference in the SDK, it will later
be nullable in a follow up change once the native API supports it.

Bug: webrtc:11164
Change-Id: I8324e6e0af996dfddfa07e3aff4ba242d9533388
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161321
Commit-Queue: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30170}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index 89fb602..8b61ecf 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -1393,7 +1393,8 @@
         "instrumentationtests/src/org/webrtc/PeerConnectionTest.java",
         "instrumentationtests/src/org/webrtc/RendererCommonTest.java",
         "instrumentationtests/src/org/webrtc/RtcCertificatePemTest.java",
-        "instrumentationtests/src/org/webrtc/RtpTranceiverTest.java",
+        "instrumentationtests/src/org/webrtc/RtpSenderTest.java",
+        "instrumentationtests/src/org/webrtc/RtpTransceiverTest.java",
         "instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java",
         "instrumentationtests/src/org/webrtc/SurfaceViewRendererOnMeasureTest.java",
         "instrumentationtests/src/org/webrtc/TestConstants.java",
diff --git a/sdk/android/api/org/webrtc/RtpParameters.java b/sdk/android/api/org/webrtc/RtpParameters.java
index 183faca..4293ce7 100644
--- a/sdk/android/api/org/webrtc/RtpParameters.java
+++ b/sdk/android/api/org/webrtc/RtpParameters.java
@@ -27,6 +27,22 @@
  * default value".
  */
 public class RtpParameters {
+  public enum DegradationPreference {
+    /** Does not degrade resolution or framerate. */
+    DISABLED,
+    /** Degrade resolution in order to maintain framerate. */
+    MAINTAIN_FRAMERATE,
+    /** Degrade framerate in order to maintain resolution. */
+    MAINTAIN_RESOLUTION,
+    /** Degrade a balance of framerate and resolution. */
+    BALANCED;
+
+    @CalledByNative("DegradationPreference")
+    static DegradationPreference fromNativeIndex(int nativeIndex) {
+      return values()[nativeIndex];
+    }
+  }
+
   public static class Encoding {
     // If non-null, this represents the RID that identifies this encoding layer.
     // RIDs are used to identify layers in simulcast.
@@ -230,20 +246,25 @@
 
   public final String transactionId;
 
+  /**
+   * When bandwidth is constrained and the RtpSender needs to choose between degrading resolution or
+   * degrading framerate, degradationPreference indicates which is preferred.
+   */
+  @Nullable public DegradationPreference degradationPreference;
+
   private final Rtcp rtcp;
 
   private final List<HeaderExtension> headerExtensions;
 
   public final List<Encoding> encodings;
-  // Codec parameters can't currently be changed between getParameters and
-  // setParameters. Though in the future it will be possible to reorder them or
-  // remove them.
+
   public final List<Codec> codecs;
 
   @CalledByNative
-  RtpParameters(String transactionId, Rtcp rtcp, List<HeaderExtension> headerExtensions,
-      List<Encoding> encodings, List<Codec> codecs) {
+  RtpParameters(String transactionId, DegradationPreference degradationPreference, Rtcp rtcp,
+      List<HeaderExtension> headerExtensions, List<Encoding> encodings, List<Codec> codecs) {
     this.transactionId = transactionId;
+    this.degradationPreference = degradationPreference;
     this.rtcp = rtcp;
     this.headerExtensions = headerExtensions;
     this.encodings = encodings;
@@ -256,6 +277,11 @@
   }
 
   @CalledByNative
+  DegradationPreference getDegradationPreference() {
+    return degradationPreference;
+  }
+
+  @CalledByNative
   public Rtcp getRtcp() {
     return rtcp;
   }
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/RtpSenderTest.java b/sdk/android/instrumentationtests/src/org/webrtc/RtpSenderTest.java
new file mode 100644
index 0000000..14d76d0
--- /dev/null
+++ b/sdk/android/instrumentationtests/src/org/webrtc/RtpSenderTest.java
@@ -0,0 +1,79 @@
+/*
+ *  Copyright 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+package org.webrtc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import java.util.Arrays;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.webrtc.RtpParameters.DegradationPreference;
+
+/** Unit-tests for {@link RtpSender}. */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class RtpSenderTest {
+  private PeerConnectionFactory factory;
+  private PeerConnection pc;
+
+  @Before
+  public void setUp() {
+    PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions
+                                         .builder(InstrumentationRegistry.getTargetContext())
+                                         .setNativeLibraryName(TestConstants.NATIVE_LIBRARY)
+                                         .createInitializationOptions());
+
+    factory = PeerConnectionFactory.builder().createPeerConnectionFactory();
+
+    PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(Arrays.asList());
+    // RtpTranceiver is part of new unified plan semantics.
+    config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
+    pc = factory.createPeerConnection(config, mock(PeerConnection.Observer.class));
+  }
+
+  /** Test checking the enum values for DegradationPreference stay consistent */
+  @Test
+  @SmallTest
+  public void testSetDegradationPreference() throws Exception {
+    RtpTransceiver transceiver = pc.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO);
+    RtpSender sender = transceiver.getSender();
+
+    RtpParameters parameters = sender.getParameters();
+    assertNotNull(parameters);
+    assertEquals(DegradationPreference.BALANCED, parameters.degradationPreference);
+
+    parameters.degradationPreference = DegradationPreference.MAINTAIN_FRAMERATE;
+    assertTrue(sender.setParameters(parameters));
+    parameters = sender.getParameters();
+    assertEquals(DegradationPreference.MAINTAIN_FRAMERATE, parameters.degradationPreference);
+
+    parameters.degradationPreference = DegradationPreference.MAINTAIN_RESOLUTION;
+    assertTrue(sender.setParameters(parameters));
+    parameters = sender.getParameters();
+    assertEquals(DegradationPreference.MAINTAIN_RESOLUTION, parameters.degradationPreference);
+
+    parameters.degradationPreference = DegradationPreference.BALANCED;
+    assertTrue(sender.setParameters(parameters));
+    parameters = sender.getParameters();
+    assertEquals(DegradationPreference.BALANCED, parameters.degradationPreference);
+
+    parameters.degradationPreference = DegradationPreference.DISABLED;
+    assertTrue(sender.setParameters(parameters));
+    parameters = sender.getParameters();
+    assertEquals(DegradationPreference.DISABLED, parameters.degradationPreference);
+  }
+}
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/RtpTranceiverTest.java b/sdk/android/instrumentationtests/src/org/webrtc/RtpTransceiverTest.java
similarity index 98%
rename from sdk/android/instrumentationtests/src/org/webrtc/RtpTranceiverTest.java
rename to sdk/android/instrumentationtests/src/org/webrtc/RtpTransceiverTest.java
index 3b03df7..fd13d11 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/RtpTranceiverTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/RtpTransceiverTest.java
@@ -28,7 +28,7 @@
 
 /** Unit-tests for {@link RtpTransceiver}. */
 @RunWith(BaseJUnit4ClassRunner.class)
-public class RtpTranceiverTest {
+public class RtpTransceiverTest {
   private PeerConnectionFactory factory;
   private PeerConnection pc;
 
diff --git a/sdk/android/src/jni/pc/rtp_parameters.cc b/sdk/android/src/jni/pc/rtp_parameters.cc
index c6dc870..4bed3f8 100644
--- a/sdk/android/src/jni/pc/rtp_parameters.cc
+++ b/sdk/android/src/jni/pc/rtp_parameters.cc
@@ -20,6 +20,28 @@
 
 namespace {
 
+webrtc::DegradationPreference JavaToNativeDegradationPreference(
+    JNIEnv* jni,
+    const JavaRef<jobject>& j_degradation_preference) {
+  std::string enum_name = GetJavaEnumName(jni, j_degradation_preference);
+
+  if (enum_name == "DISABLED")
+    return webrtc::DegradationPreference::DISABLED;
+
+  if (enum_name == "MAINTAIN_FRAMERATE")
+    return webrtc::DegradationPreference::MAINTAIN_FRAMERATE;
+
+  if (enum_name == "MAINTAIN_RESOLUTION")
+    return webrtc::DegradationPreference::MAINTAIN_RESOLUTION;
+
+  if (enum_name == "BALANCED")
+    return webrtc::DegradationPreference::BALANCED;
+
+  RTC_CHECK(false) << "Unexpected DegradationPreference enum_name "
+                   << enum_name;
+  return webrtc::DegradationPreference::DISABLED;
+}
+
 ScopedJavaLocalRef<jobject> NativeToJavaRtpEncodingParameter(
     JNIEnv* env,
     const RtpEncodingParameters& encoding) {
@@ -103,6 +125,13 @@
       Java_RtpParameters_getTransactionId(jni, j_parameters);
   parameters.transaction_id = JavaToNativeString(jni, j_transaction_id);
 
+  ScopedJavaLocalRef<jobject> j_degradation_preference =
+      Java_RtpParameters_getDegradationPreference(jni, j_parameters);
+  if (!IsNull(jni, j_degradation_preference)) {
+    parameters.degradation_preference =
+        JavaToNativeDegradationPreference(jni, j_degradation_preference);
+  }
+
   ScopedJavaLocalRef<jobject> j_rtcp =
       Java_RtpParameters_getRtcp(jni, j_parameters);
   ScopedJavaLocalRef<jstring> j_rtcp_cname = Java_Rtcp_getCname(jni, j_rtcp);
@@ -158,6 +187,8 @@
     const RtpParameters& parameters) {
   return Java_RtpParameters_Constructor(
       env, NativeToJavaString(env, parameters.transaction_id),
+      Java_DegradationPreference_fromNativeIndex(
+          env, static_cast<int>(parameters.degradation_preference)),
       NativeToJavaRtpRtcpParameters(env, parameters.rtcp),
       NativeToJavaList(env, parameters.header_extensions,
                        &NativeToJavaRtpHeaderExtensionParameter),