diff --git a/webrtc/androidjunit/OWNERS b/webrtc/androidjunit/OWNERS new file mode 100644 index 0000000000..299e8b20ec --- /dev/null +++ b/webrtc/androidjunit/OWNERS @@ -0,0 +1,2 @@ +magjed@webrtc.org +sakal@webrtc.org diff --git a/webrtc/androidjunit/src/org/webrtc/CameraEnumerationTest.java b/webrtc/androidjunit/src/org/webrtc/CameraEnumerationTest.java new file mode 100644 index 0000000000..b1ebb6c360 --- /dev/null +++ b/webrtc/androidjunit/src/org/webrtc/CameraEnumerationTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016 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.webrtc.CameraEnumerationAndroid.getClosestSupportedFramerateRange; + +import org.webrtc.CameraEnumerationAndroid.CaptureFormat; +import org.webrtc.CameraEnumerationAndroid.CaptureFormat.FramerateRange; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.Arrays; + +/** + * Tests for CameraEnumerationAndroid. + */ +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class CameraEnumerationTest { + @Test + public void testGetClosestSupportedFramerateRange() { + assertEquals(new FramerateRange(10000, 30000), + getClosestSupportedFramerateRange( + Arrays.asList(new FramerateRange(10000, 30000), + new FramerateRange(30000, 30000)), + 30 /* requestedFps */)); + + assertEquals(new FramerateRange(10000, 20000), + getClosestSupportedFramerateRange( + Arrays.asList(new FramerateRange(0, 30000), + new FramerateRange(10000, 20000), + new FramerateRange(14000, 16000), + new FramerateRange(15000, 15000)), + 15 /* requestedFps */)); + + assertEquals(new FramerateRange(10000, 20000), + getClosestSupportedFramerateRange( + Arrays.asList(new FramerateRange(15000, 15000), + new FramerateRange(10000, 20000), + new FramerateRange(10000, 30000)), + 10 /* requestedFps */)); + } +} diff --git a/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java b/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java index 2fa685d1fb..87b9a40b62 100644 --- a/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java +++ b/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java @@ -181,15 +181,37 @@ public class CameraEnumerationAndroid { } } + // Prefer a fps range with an upper bound close to |framerate|. Also prefer a fps range with a low + // lower bound, to allow the framerate to fluctuate based on lightning conditions. public static CaptureFormat.FramerateRange getClosestSupportedFramerateRange( List supportedFramerates, final int requestedFps) { return Collections.min(supportedFramerates, new ClosestComparator() { - private static final int MAX_FPS_WEIGHT = 10; + // Progressive penalty if the upper bound is further away than |MAX_FPS_DIFF_THRESHOLD| + // from requested. + private static final int MAX_FPS_DIFF_THRESHOLD = 5000; + private static final int MAX_FPS_LOW_DIFF_WEIGHT = 1; + private static final int MAX_FPS_HIGH_DIFF_WEIGHT = 3; + + // Progressive penalty if the lower bound is bigger than |MIN_FPS_THRESHOLD|. + private static final int MIN_FPS_THRESHOLD = 8000; + private static final int MIN_FPS_LOW_VALUE_WEIGHT = 1; + private static final int MIN_FPS_HIGH_VALUE_WEIGHT = 4; + + // Use one weight for small |value| less than |threshold|, and another weight above. + private int progressivePenalty(int value, int threshold, int lowWeight, int highWeight) { + return (value < threshold) + ? value * lowWeight + : threshold * lowWeight + (value - threshold) * highWeight; + } @Override int diff(CaptureFormat.FramerateRange range) { - return range.min + MAX_FPS_WEIGHT * abs(requestedFps * 1000 - range.max); + final int minFpsError = progressivePenalty(range.min, + MIN_FPS_THRESHOLD, MIN_FPS_LOW_VALUE_WEIGHT, MIN_FPS_HIGH_VALUE_WEIGHT); + final int maxFpsError = progressivePenalty(Math.abs(requestedFps * 1000 - range.max), + MAX_FPS_DIFF_THRESHOLD, MAX_FPS_LOW_DIFF_WEIGHT, MAX_FPS_HIGH_DIFF_WEIGHT); + return minFpsError + maxFpsError; } }); } diff --git a/webrtc/webrtc_tests.gypi b/webrtc/webrtc_tests.gypi index 4ade4728f4..22a8bf2686 100644 --- a/webrtc/webrtc_tests.gypi +++ b/webrtc/webrtc_tests.gypi @@ -353,6 +353,28 @@ '<(apk_tests_path):webrtc_nonparallel_tests_apk', ], }, + { + 'target_name': 'android_junit_tests', + 'type': 'none', + 'dependencies': [ + '<(webrtc_root)/api/api.gyp:libjingle_peerconnection_java', + '<(DEPTH)/base/base.gyp:base_java', + '<(DEPTH)/base/base.gyp:base_java_test_support', + '<(DEPTH)/base/base.gyp:base_junit_test_support', + ], + 'variables': { + 'main_class': 'org.chromium.testing.local.JunitTestMain', + 'src_paths': [ + 'androidjunit/', + ], + 'test_type': 'junit', + 'wrapper_script_name': 'helper/<(_target_name)', + }, + 'includes': [ + '../build/android/test_runner.gypi', + '../build/host_jar.gypi', + ], + }, ], 'conditions': [ ['test_isolation_mode != "noop"',