Add scaleResolutionDownBy to RtpParameters.Encoding in Android SDK.

Bug: webrtc:10069
Change-Id: I8130836c495d5584ca3e11e9e3155916b871ab21
Reviewed-on: https://webrtc-review.googlesource.com/c/120926
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Commit-Queue: Mirta Dvornicic <mirtad@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26535}
diff --git a/sdk/android/api/org/webrtc/RtpParameters.java b/sdk/android/api/org/webrtc/RtpParameters.java
index 5158c13..5fe36ef 100644
--- a/sdk/android/api/org/webrtc/RtpParameters.java
+++ b/sdk/android/api/org/webrtc/RtpParameters.java
@@ -11,6 +11,7 @@
 package org.webrtc;
 
 import android.support.annotation.Nullable;
+import java.lang.Double;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -40,18 +41,22 @@
     @Nullable public Integer maxFramerate;
     // The number of temporal layers for video.
     @Nullable public Integer numTemporalLayers;
+    // If non-null, scale the width and height down by this factor for video. If null,
+    // implementation default scaling factor will be used.
+    @Nullable public Double scaleResolutionDownBy;
     // SSRC to be used by this encoding.
     // Can't be changed between getParameters/setParameters.
     public Long ssrc;
 
     @CalledByNative("Encoding")
     Encoding(boolean active, Integer maxBitrateBps, Integer minBitrateBps, Integer maxFramerate,
-        Integer numTemporalLayers, Long ssrc) {
+        Integer numTemporalLayers, Double scaleResolutionDownBy, Long ssrc) {
       this.active = active;
       this.maxBitrateBps = maxBitrateBps;
       this.minBitrateBps = minBitrateBps;
       this.maxFramerate = maxFramerate;
       this.numTemporalLayers = numTemporalLayers;
+      this.scaleResolutionDownBy = scaleResolutionDownBy;
       this.ssrc = ssrc;
     }
 
@@ -84,6 +89,12 @@
       return numTemporalLayers;
     }
 
+    @Nullable
+    @CalledByNative("Encoding")
+    Double getScaleResolutionDownBy() {
+      return scaleResolutionDownBy;
+    }
+
     @CalledByNative("Encoding")
     Long getSsrc() {
       return ssrc;
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
index e8859e0..c4ff285 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
@@ -10,6 +10,7 @@
 
 package org.webrtc;
 
+import static com.google.common.truth.Truth.assertThat;
 import static java.util.Collections.singletonList;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -148,6 +149,9 @@
     // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression.
     @SuppressWarnings("NoSynchronizedMethodCheck")
     public synchronized void onFrame(VideoFrame frame) {
+      if (expectedFramesDelivered <= 0) {
+        return;
+      }
       assertTrue(expectedWidth > 0);
       assertTrue(expectedHeight > 0);
       assertEquals(expectedWidth, frame.getRotatedWidth());
@@ -1025,11 +1029,13 @@
     assertNull(rtpParameters.encodings.get(0).minBitrateBps);
     assertNull(rtpParameters.encodings.get(0).maxFramerate);
     assertNull(rtpParameters.encodings.get(0).numTemporalLayers);
+    assertNull(rtpParameters.encodings.get(0).scaleResolutionDownBy);
 
     rtpParameters.encodings.get(0).maxBitrateBps = 300000;
     rtpParameters.encodings.get(0).minBitrateBps = 100000;
     rtpParameters.encodings.get(0).maxFramerate = 20;
     rtpParameters.encodings.get(0).numTemporalLayers = 2;
+    rtpParameters.encodings.get(0).scaleResolutionDownBy = 2.0;
     assertTrue(videoSender.setParameters(rtpParameters));
 
     // Create a DTMF sender.
@@ -1044,6 +1050,7 @@
     assertEquals(100000, (int) rtpParameters.encodings.get(0).minBitrateBps);
     assertEquals(20, (int) rtpParameters.encodings.get(0).maxFramerate);
     assertEquals(2, (int) rtpParameters.encodings.get(0).numTemporalLayers);
+    assertThat(rtpParameters.encodings.get(0).scaleResolutionDownBy).isEqualTo(2.0);
 
     // Test send & receive UTF-8 text.
     answeringExpectations.expectMessage(
diff --git a/sdk/android/native_api/jni/java_types.cc b/sdk/android/native_api/jni/java_types.cc
index 5617b18..107e4e0 100644
--- a/sdk/android/native_api/jni/java_types.cc
+++ b/sdk/android/native_api/jni/java_types.cc
@@ -132,6 +132,14 @@
   return JNI_Boolean::Java_Boolean_booleanValue(jni, boolean);
 }
 
+absl::optional<double> JavaToNativeOptionalDouble(
+    JNIEnv* jni,
+    const JavaRef<jobject>& j_double) {
+  if (IsNull(jni, j_double))
+    return absl::nullopt;
+  return JNI_Double::Java_Double_doubleValue(jni, j_double);
+}
+
 absl::optional<int32_t> JavaToNativeOptionalInt(
     JNIEnv* jni,
     const JavaRef<jobject>& integer) {
@@ -194,6 +202,12 @@
   return NativeToJavaString(jni, str.c_str());
 }
 
+ScopedJavaLocalRef<jobject> NativeToJavaDouble(
+    JNIEnv* jni,
+    const absl::optional<double>& optional_double) {
+  return optional_double ? NativeToJavaDouble(jni, *optional_double) : nullptr;
+}
+
 ScopedJavaLocalRef<jobject> NativeToJavaInteger(
     JNIEnv* jni,
     const absl::optional<int32_t>& optional_int) {
@@ -259,8 +273,10 @@
 ScopedJavaLocalRef<jobjectArray> NativeToJavaDoubleArray(
     JNIEnv* env,
     const std::vector<double>& container) {
+  ScopedJavaLocalRef<jobject> (*convert_function)(JNIEnv*, double) =
+      &NativeToJavaDouble;
   return NativeToJavaObjectArray(env, container, java_lang_Double_clazz(env),
-                                 &NativeToJavaDouble);
+                                 convert_function);
 }
 
 ScopedJavaLocalRef<jobjectArray> NativeToJavaIntegerArray(
@@ -282,12 +298,12 @@
 ScopedJavaLocalRef<jobjectArray> NativeToJavaStringArray(
     JNIEnv* env,
     const std::vector<std::string>& container) {
-  ScopedJavaLocalRef<jstring> (*convert)(JNIEnv*, const std::string&) =
+  ScopedJavaLocalRef<jstring> (*convert_function)(JNIEnv*, const std::string&) =
       &NativeToJavaString;
   return NativeToJavaObjectArray(
       env, container,
       static_cast<jclass>(jni::Java_JniHelper_getStringClass(env).obj()),
-      convert);
+      convert_function);
 }
 
 JavaListBuilder::JavaListBuilder(JNIEnv* env)
diff --git a/sdk/android/native_api/jni/java_types.h b/sdk/android/native_api/jni/java_types.h
index c8f0c60..955911c 100644
--- a/sdk/android/native_api/jni/java_types.h
+++ b/sdk/android/native_api/jni/java_types.h
@@ -129,6 +129,9 @@
 
 absl::optional<bool> JavaToNativeOptionalBool(JNIEnv* jni,
                                               const JavaRef<jobject>& boolean);
+absl::optional<double> JavaToNativeOptionalDouble(
+    JNIEnv* jni,
+    const JavaRef<jobject>& j_double);
 absl::optional<int32_t> JavaToNativeOptionalInt(
     JNIEnv* jni,
     const JavaRef<jobject>& integer);
@@ -196,6 +199,9 @@
 ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni,
                                                const std::string& str);
 
+ScopedJavaLocalRef<jobject> NativeToJavaDouble(
+    JNIEnv* jni,
+    const absl::optional<double>& optional_double);
 ScopedJavaLocalRef<jobject> NativeToJavaInteger(
     JNIEnv* jni,
     const absl::optional<int32_t>& optional_int);
diff --git a/sdk/android/src/jni/pc/rtp_parameters.cc b/sdk/android/src/jni/pc/rtp_parameters.cc
index 25adb4c..9b3c070 100644
--- a/sdk/android/src/jni/pc/rtp_parameters.cc
+++ b/sdk/android/src/jni/pc/rtp_parameters.cc
@@ -28,6 +28,7 @@
       NativeToJavaInteger(env, encoding.min_bitrate_bps),
       NativeToJavaInteger(env, encoding.max_framerate),
       NativeToJavaInteger(env, encoding.num_temporal_layers),
+      NativeToJavaDouble(env, encoding.scale_resolution_down_by),
       encoding.ssrc ? NativeToJavaLong(env, *encoding.ssrc) : nullptr);
 }
 
@@ -77,6 +78,10 @@
       Java_Encoding_getNumTemporalLayers(jni, j_encoding_parameters);
   encoding.num_temporal_layers =
       JavaToNativeOptionalInt(jni, j_num_temporal_layers);
+  ScopedJavaLocalRef<jobject> j_scale_resolution_down_by =
+      Java_Encoding_getScaleResolutionDownBy(jni, j_encoding_parameters);
+  encoding.scale_resolution_down_by =
+      JavaToNativeOptionalDouble(jni, j_scale_resolution_down_by);
   ScopedJavaLocalRef<jobject> j_ssrc =
       Java_Encoding_getSsrc(jni, j_encoding_parameters);
   if (!IsNull(jni, j_ssrc))