async applyConstraints resizeMode none

Test

by jib1

HTML

<button id="go">Go!</button><br><br>
Camera: <select id="camera"></select><br>
Microphone: <select id="microphone"></select><br>
Height <input id="number" type="number" min="2" max="2160" value="720">
<input id="range" type="range" min="0" max="2160" value="720">
<div id="div2"><p>0 x 0 x 0.0</p></div>
<div id="div"></div>
<video id="video" autoplay></video>

JavaScript

const console = {log: msg => div.innerHTML += `${msg}<br>`};
const update = msg => div2.innerHTML = `<p>${msg}</p>`;
const wait = ms => new Promise(r => setTimeout(r, ms));
const frames = v => v.mozPaintedFrames || v.webkitDecodedFrameCount || 0;

range.oninput = () => apply(number.value = range.value);
number.oninput = () => apply(range.value = number.value);

let track, applying = false, height = 0;

async function apply(h) {
  height = h;
  if (applying) return;
  try {
    applying = true;
    do {
      h = height;
      await track.applyConstraints({height, resizeMode: "none"});
    } while (h != height);
  } catch (e) {
    console.log(e);
  } finally {
    applying = false;
  }
}

go.onclick = async () => {
  try {
    video.srcObject = await getUserMedia({audio: true, video: true });
    updateSelectors(video.srcObject.getTracks().map(t => t.getSettings().deviceId));
    await new Promise(r => video.onloadedmetadata = r);
    number.value = range.value = track.getSettings().height;
    let t1 = 0, t2 = 1, f1 = 0, f2 = 0;
    while (true) {
      await wait(500);
      t2 = video.currentTime; f2 = frames(video);
      const hz = (f2 - f1) / (t2 - t1);
      update(`${video.videoWidth} x ${video.videoHeight} x ${hz.toFixed(2)}`);
      t1 = t2; f1 = f2;
    }
  } catch(e) {
    console.log(e);
  }
};

async function getUserMedia({video, audio}) {
  if (video === true) {
    video = {deviceId: localStorage.video, height: range.value};
  }
  if (audio === true) {
    audio = {deviceId: localStorage.audio};
  }
  const stream = await navigator.mediaDevices.getUserMedia({video, audio});
  for (const track of stream.getTracks()) {
    localStorage[track.kind] = track.getSettings().deviceId;
  }
  track = stream.getVideoTracks()[0];
  return stream;
}

async function replaceUserMedia(constraints, ...oldTracks) {
  try {
     return await getUserMedia(constraints);
  } catch (e) {
    if (e.name != "NotReadableError") throw e;
    for (const track of oldTracks)...