[Media Router] Revise capture resolution selection algorithm.
This CL does a few things.
1. Use physical pixel dimensions as the input to the max resolution algorithm.
2. Accounts for portrait mode tablets/convertibles by converting dimensions to
landscape mode.
3. Simplifies the max resolution selection algorithm to find the maximum 16:9
capture resolution that downscales the longer dimension of the screen
dimensions, constrained below by the minimum capture dimensions and above by
1920x1080 (as capture-beyond-full-HD is uncharted territory).
This also adds several test cases for the max resolution setting algorithm.
PiperOrigin-RevId: 250015772
diff --git a/mirror_services/mirror_settings.js b/mirror_services/mirror_settings.js
index 1caad6a..ae720ef 100644
--- a/mirror_services/mirror_settings.js
+++ b/mirror_services/mirror_settings.js
@@ -29,8 +29,6 @@
RTX: 'rtx'
};
-
-
/**
* Settings that affect capture and transport (via Cast Streaming or WebRTC).
* Generally, these should all be left unchanged from their defaults.
@@ -65,19 +63,33 @@
*/
mr.mirror.Settings = class {
constructor() {
+ // When all streaming endpoints support adaptive capture and/or we ship VP9
+ // support, we plan to raise these limits.
+ /**
+ * The absolute maximum width we are willing to capture.
+ * @const {number}
+ */
+ this.maxCaptureWidth = 1920;
+
+ /**
+ * The absolute maximum height we are willing to capture.
+ * @const {number}
+ */
+ this.maxCaptureHeight = 1080;
+
/**
* Maximum video width in pixels.
*
* @export {number}
*/
- this.maxWidth = 1920;
+ this.maxWidth = this.maxCaptureWidth;
/**
* Maximum video height in pixels.
*
* @export {number}
*/
- this.maxHeight = 1080;
+ this.maxHeight = this.maxCaptureHeight;
/**
* Minimum video width in pixels.
@@ -300,8 +312,15 @@
clampMaxDimensionsToScreenSize_() {
const widthStep = 160;
const heightStep = 90;
- const screenWidth = mr.mirror.Settings.getScreenWidth();
- const screenHeight = mr.mirror.Settings.getScreenHeight();
+ let screenWidth = mr.mirror.Settings.getScreenWidth();
+ let screenHeight = mr.mirror.Settings.getScreenHeight();
+
+ // If the device is in portrait mode, then set capture dimensions
+ // based on landscape orientation. Otherwise the chosen capture dimensions
+ // are artificially low.
+ if (screenHeight > screenWidth) {
+ [screenWidth, screenHeight] = [screenHeight, screenWidth];
+ }
const x = this.maxWidth * screenHeight;
const y = this.maxHeight * screenWidth;
let clampedWidth = 0;
@@ -383,12 +402,12 @@
/** @return {number} */
static getScreenWidth() {
- return screen.width;
+ return Math.round(screen.width * window.devicePixelRatio);
}
/** @return {number} */
static getScreenHeight() {
- return screen.height;
+ return Math.round(screen.height * window.devicePixelRatio);
}
};
diff --git a/mirror_services/mirror_settings_test.js b/mirror_services/mirror_settings_test.js
index 066e92f..09d5831 100644
--- a/mirror_services/mirror_settings_test.js
+++ b/mirror_services/mirror_settings_test.js
@@ -46,7 +46,34 @@
expect(settings.toJsonString()).toEqual(jsonBefore);
});
- it('clamps max dimensions to 1920x1080 screen size', function() {
+ it('clamps max dimensions from 1280x800 (16:10) screen size', function() {
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(1280);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(800);
+ const settings = new mr.mirror.Settings();
+ settings.makeFinalAdjustmentsAndFreeze();
+ expect(settings.maxWidth).toBe(1280);
+ expect(settings.maxHeight).toBe(720);
+ });
+
+ it('clamps max dimensions from 1366x768 screen size', function() {
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(1366);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(768);
+ const settings = new mr.mirror.Settings();
+ settings.makeFinalAdjustmentsAndFreeze();
+ expect(settings.maxWidth).toBe(1280);
+ expect(settings.maxHeight).toBe(720);
+ });
+
+ it('clamps max dimensions from 768x1366 screen size', function() {
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(768);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(1366);
+ const settings = new mr.mirror.Settings();
+ settings.makeFinalAdjustmentsAndFreeze();
+ expect(settings.maxWidth).toBe(1280);
+ expect(settings.maxHeight).toBe(720);
+ });
+
+ it('clamps max dimensions from 1920x1080 screen size', function() {
spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(1920);
spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(1080);
const settings = new mr.mirror.Settings();
@@ -55,13 +82,51 @@
expect(settings.maxHeight).toBe(1080);
});
- it('clamps max dimensions to 1366x768 screen size', function() {
- spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(1366);
- spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(768);
+ it('clamps max dimensions from 1546x2048 (2:3) screen size', function() {
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(1546);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(2048);
const settings = new mr.mirror.Settings();
settings.makeFinalAdjustmentsAndFreeze();
- expect(settings.maxWidth).toBe(1280);
- expect(settings.maxHeight).toBe(720);
+ expect(settings.maxWidth).toBe(1920);
+ expect(settings.maxHeight).toBe(1080);
+ });
+
+ it('clamps max dimensions from 2399x1598 (3:2) screen size', function() {
+ // This odd dimension is what is actually reported by Pixelbook.
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(2399);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(1598);
+ const settings = new mr.mirror.Settings();
+ settings.makeFinalAdjustmentsAndFreeze();
+ expect(settings.maxWidth).toBe(1920);
+ expect(settings.maxHeight).toBe(1080);
+ });
+
+ it('clamps max dimensions from 2560x1080 (21:9) screen size', function() {
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(2560);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(1080);
+ const settings = new mr.mirror.Settings();
+ settings.makeFinalAdjustmentsAndFreeze();
+ expect(settings.maxWidth).toBe(1920);
+ expect(settings.maxHeight).toBe(1080);
+ });
+
+ it('clamps max dimensions from 2560x1600 (16:10 "retina") screen size',
+ function() {
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(2560);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(1080);
+ const settings = new mr.mirror.Settings();
+ settings.makeFinalAdjustmentsAndFreeze();
+ expect(settings.maxWidth).toBe(1920);
+ expect(settings.maxHeight).toBe(1080);
+ });
+
+ it('clamps max dimensions from 3840x2160 screen size', function() {
+ spyOn(mr.mirror.Settings, 'getScreenWidth').and.returnValue(3840);
+ spyOn(mr.mirror.Settings, 'getScreenHeight').and.returnValue(2160);
+ const settings = new mr.mirror.Settings();
+ settings.makeFinalAdjustmentsAndFreeze();
+ expect(settings.maxWidth).toBe(1920);
+ expect(settings.maxHeight).toBe(1080);
});
it('returns min size matching aspect ratio of max size', function() {