diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/mst-content-hint | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/mst-content-hint')
5 files changed, 391 insertions, 0 deletions
diff --git a/testing/web-platform/tests/mst-content-hint/META.yml b/testing/web-platform/tests/mst-content-hint/META.yml new file mode 100644 index 0000000000..7f79eccbaa --- /dev/null +++ b/testing/web-platform/tests/mst-content-hint/META.yml @@ -0,0 +1,3 @@ +spec: https://w3c.github.io/mst-content-hint/ +suggested_reviewers: + - alvestrand diff --git a/testing/web-platform/tests/mst-content-hint/MediaStreamTrack-contentHint.html b/testing/web-platform/tests/mst-content-hint/MediaStreamTrack-contentHint.html new file mode 100644 index 0000000000..98c88e66ea --- /dev/null +++ b/testing/web-platform/tests/mst-content-hint/MediaStreamTrack-contentHint.html @@ -0,0 +1,111 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<canvas id="canvas"> +</canvas> +<script> + +function createAudioTrack() { + ac = new AudioContext(); + var osc = ac.createOscillator(); + var dest = ac.createMediaStreamDestination(); + osc.connect(dest); + audio_track = dest.stream.getAudioTracks()[0]; + + assert_equals(audio_track.kind, "audio"); + return audio_track; +} + +function createVideoTrack() { + canvas = document.getElementById("canvas"); + video_track = canvas.captureStream().getVideoTracks()[0]; + + assert_equals(video_track.kind, "video"); + return video_track; +} + +test(t => { + audio_track = createAudioTrack(); + assert_equals("", audio_track.contentHint); + + video_track = createVideoTrack(); + assert_equals("", video_track.contentHint); +}, "Tracks have empty default content hint"); + +test(t => { + audio_track = createAudioTrack(); + audio_track.contentHint = "speech"; + assert_equals(audio_track.contentHint, "speech"); + audio_track.contentHint = "music"; + assert_equals(audio_track.contentHint, "music"); + audio_track.contentHint = ""; + assert_equals(audio_track.contentHint, ""); +}, "Accepts valid audio contentHints"); + +test(t => { + audio_track = createAudioTrack(); + audio_track.contentHint = "speech"; + assert_equals(audio_track.contentHint, "speech"); + audio_track.contentHint = "motion"; + assert_equals(audio_track.contentHint, "speech", + "Audio tracks should ignore video-only contentHints."); + audio_track.contentHint = "bogus"; + assert_equals(audio_track.contentHint, "speech", + "Audio tracks should ignore garbage contentHints"); +}, "Audio tracks ignore invalid/video contentHints"); + +test(t => { + video_track = createVideoTrack(); + video_track.contentHint = "motion"; + assert_equals(video_track.contentHint, "motion"); + video_track.contentHint = "detail"; + assert_equals(video_track.contentHint, "detail"); + video_track.contentHint = "text"; + assert_equals(video_track.contentHint, "text"); + video_track.contentHint = ""; + assert_equals(video_track.contentHint, ""); +}, "Accepts valid video contentHints"); + +test(t => { + video_track = createVideoTrack(); + video_track.contentHint = "motion"; + assert_equals(video_track.contentHint, "motion"); + video_track.contentHint = "speech"; + assert_equals(video_track.contentHint, "motion", + "Video tracks should ignore audio-only contentHints."); + video_track.contentHint = "bogus"; + assert_equals(video_track.contentHint, "motion", + "Video tracks should ignore garbage contentHints"); +}, "Video tracks ignore invalid/audio contentHints"); + +test(t => { + video_track = createVideoTrack(); + video_track.contentHint = "motion"; + assert_equals(video_track.contentHint, "motion"); + + // Cloning a track should preserve contentHint. + video_track_clone = video_track.clone(); + assert_equals(video_track_clone.contentHint, "motion"); + + // Changing a cloned track's contentHint should not change the original. + video_track_clone.contentHint = "detail"; + assert_equals(video_track_clone.contentHint, "detail"); + assert_equals(video_track.contentHint, "motion"); +}, "Cloned video tracks have separate contentHints"); + +test(t => { + audio_track = createAudioTrack(); + audio_track.contentHint = "speech"; + assert_equals(audio_track.contentHint, "speech"); + + // Cloning a track should preserve contentHint. + audio_track_clone = audio_track.clone(); + assert_equals(audio_track_clone.contentHint, "speech"); + + // Changing a cloned track's contentHint should not change the original. + audio_track_clone.contentHint = "music"; + assert_equals(audio_track_clone.contentHint, "music"); + assert_equals(audio_track.contentHint, "speech"); +}, "Cloned audio tracks have separate contentHints"); + +</script> diff --git a/testing/web-platform/tests/mst-content-hint/RTCRtpSendParameters-degradationEffect.html b/testing/web-platform/tests/mst-content-hint/RTCRtpSendParameters-degradationEffect.html new file mode 100644 index 0000000000..a2da6cd139 --- /dev/null +++ b/testing/web-platform/tests/mst-content-hint/RTCRtpSendParameters-degradationEffect.html @@ -0,0 +1,129 @@ +<!doctype html> +<meta charset=utf-8> +<meta name="timeout" content="long"> +<title>RTCRtpSendParameters degradationPreference effect</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../webrtc/RTCPeerConnection-helper.js"></script> +<script> + 'use strict'; + +// This file contains tests that check that degradation preference +// actually has the desired effect. These tests take a long time to run. + +// The signal generator will generate a video stream with at least this +// many bits per second if unconstrained. +const minUnconstrainedBandwidth = 30000; + +// Returns incoming bandwidth usage between stats1 and stats2 +// in bits per second. +function bandwidth(stats1, stats2) { + if (!stats1 || !stats2) { + return null; + } + const transport1 = [...stats1.values()].filter(({type}) => type === 'transport')[0]; + const transport2 = [...stats2.values()].filter(({type}) => type === 'transport')[0]; + const bytes = transport2.bytesReceived - transport1.bytesReceived; + // If time interval is too short for proper measurement, return null. + if (transport1.timestamp > transport2.timestamp - 100) { + return null; + } + // Multiply by 1000 to get per second, multiply by 8 to get bits. + const bandwidth = 1000 * 8 * bytes / + (transport2.timestamp - transport1.timestamp); + return bandwidth; +} + +let oldStats; + +// Returns tuple of { bandwidth, fps, x-res, y-res } +// Updates oldStats. +async function measureStuff(pc) { + const stats = await pc.getStats(); + if (!oldStats) { + oldStats = stats; + return {}; + } + // RTCInboundStreamStats + const oldRtpList = [...oldStats.values()].filter(({type}) => type === 'inbound-rtp'); + const inboundRtpList = [...stats.values()].filter(({type}) => type === 'inbound-rtp'); + const oldRtp = oldRtpList[0]; + const inboundRtp = inboundRtpList[0]; + const fps = 1000.0 * (inboundRtp.framesReceived - oldRtp.framesReceived) / + (inboundRtp.timestamp - oldRtp.timestamp); + const result = { + bandwidth: bandwidth(oldStats, stats), + fps: fps, + width: inboundRtp.frameWidth, + height: inboundRtp.frameHeight + }; + oldStats = stats; + if (!result.bandwidth) { + return {}; + } + // Unbreak for debugging. + // con sole.log('Measure: ', performance.now(), " ", JSON.stringify(result)); + return result; +} + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const stream = await getNoiseStream({video: true}); + t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); + const track = stream.getTracks()[0]; + const { sender } = pc1.addTransceiver(track); + + let param = sender.getParameters(); + + param.degradationPreference = 'maintain-framerate'; + await sender.setParameters(param); + + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + + exchangeIceCandidates(pc1, pc2); + await exchangeOfferAnswer(pc1, pc2); + await listenToConnected(pc1); + // Allow the keyframe to pass. + await new Promise(r => t.step_timeout(r, 1000)); + // Wait a few seconds to allow things to settle (rampup) + // We know that the generator is supposed to produce 640x480 + // at 10 fps with a bandwidth exceeding 30 kbits/second. + await t.step_wait(async () => { + const measure = await measureStuff(pc2); + return (measure.bandwidth > minUnconstrainedBandwidth && + measure.width == 640 && + measure.fps > 9); + }, 'Test error: Preconditions not achieved', 30000, 500); + + // Measure BW, resolution and frame rate over one second + // after measurements have stabilized. + await new Promise(r => t.step_timeout(r, 1000)); + const stats1 = await measureStuff(pc2); + + // Constrain BW to 1/2 of measured value + const newBandwidth = stats1.bandwidth / 2; + // Guard against inappropriate bandwidth + assert_greater_than(newBandwidth, minUnconstrainedBandwidth/2, + "Test error: Constraint too low"); + + const parameters = sender.getParameters(); + parameters.encodings[0].maxBitrate = newBandwidth; + await sender.setParameters(parameters); + // Wait until the expected result happens. + const kBandwidthMargin = 1.3; + // It takes time to adapt to a new bandwidth, time to scale down, + // and time to acknowledge that framerate should not be reduced. + // Measured time is around 16 seconds. + await t.step_wait(async () => { + let measure = await measureStuff(pc2); + return (measure.bandwidth && + measure.bandwidth < newBandwidth * kBandwidthMargin && + measure.width < stats1.width && + measure.fps > stats1.fps * 0.9); + }, 'Adaptation did not succeed', + 30000, 500); +}, 'Maintain-framerate reduces resolution on bandwidth cut', { timeout: 35000 }); + +</script> diff --git a/testing/web-platform/tests/mst-content-hint/RTCRtpSendParameters-degradationPreference.html b/testing/web-platform/tests/mst-content-hint/RTCRtpSendParameters-degradationPreference.html new file mode 100644 index 0000000000..3573bb5876 --- /dev/null +++ b/testing/web-platform/tests/mst-content-hint/RTCRtpSendParameters-degradationPreference.html @@ -0,0 +1,129 @@ +<!doctype html> +<meta charset=utf-8> +<title>RTCRtpSendParameters degradationPreference</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + 'use strict'; + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const { sender } = pc.addTransceiver('video'); + + let param = sender.getParameters(); + + assert_equals(param.degradationPreference, undefined, + 'Expect initial param.degradationPreference to be undefined'); + + param.degradationPreference = 'maintain-framerate'; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, 'maintain-framerate'); + + param.degradationPreference = 'maintain-resolution'; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, 'maintain-resolution'); + + param.degradationPreference = 'balanced'; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, 'balanced'); + + param.degradationPreference = undefined; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, undefined); +}, 'setParameters with degradationPreference set should succeed on video transceiver'); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const { sender } = pc.addTransceiver('video'); + + let param = sender.getParameters(); + + assert_equals(param.degradationPreference, undefined, + 'Expect initial param.degradationPreference to be undefined'); + + param.degradationPreference = undefined; + + await sender.setParameters(param); + + param = sender.getParameters(); + assert_equals(param.degradationPreference, undefined); +}, 'setParameters with degradationPreference unset should succeed on video transceiver'); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const { sender } = pc.addTransceiver('video'); + + let param = sender.getParameters(); + param.degradationPreference = 'invalid'; + + return promise_rejects_js(t, TypeError, sender.setParameters(param)); +}, 'setParameters with invalid degradationPreference should throw TypeError on video transceiver'); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const { sender } = pc.addTransceiver('audio'); + + let param = sender.getParameters(); + + assert_equals(param.degradationPreference, undefined, + 'Expect initial param.degradationPreference to be undefined'); + + param.degradationPreference = 'maintain-framerate'; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, 'maintain-framerate'); + + param.degradationPreference = 'maintain-resolution'; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, 'maintain-resolution'); + + param.degradationPreference = 'balanced'; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, 'balanced'); + + param.degradationPreference = undefined; + await sender.setParameters(param); + param = sender.getParameters(); + assert_equals(param.degradationPreference, undefined); +}, 'setParameters with degradationPreference set should succeed on audio transceiver'); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const { sender } = pc.addTransceiver('audio'); + + let param = sender.getParameters(); + + assert_equals(param.degradationPreference, undefined, + 'Expect initial param.degradationPreference to be undefined'); + + param.degradationPreference = undefined; + + await sender.setParameters(param); + + param = sender.getParameters(); + assert_equals(param.degradationPreference, undefined); +}, 'setParameters with degradationPreference unset should succeed on audio transceiver'); + +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const { sender } = pc.addTransceiver('audio'); + + let param = sender.getParameters(); + param.degradationPreference = 'invalid'; + + return promise_rejects_js(t, TypeError, sender.setParameters(param)); +}, 'setParameters with invalid degradationPreference should throw TypeError on audio transceiver'); + +</script> diff --git a/testing/web-platform/tests/mst-content-hint/idlharness.window.js b/testing/web-platform/tests/mst-content-hint/idlharness.window.js new file mode 100644 index 0000000000..ef0e5e9812 --- /dev/null +++ b/testing/web-platform/tests/mst-content-hint/idlharness.window.js @@ -0,0 +1,19 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: script=/webrtc/RTCPeerConnection-helper.js + +'use strict'; + +idl_test( + ['mst-content-hint'], + ['mediacapture-streams', 'webrtc', 'dom'], + async idl_array => { + idl_array.add_objects({ + MediaStreamTrack: ['audioTrack', 'videoTrack'], + }); + + const stream = await getNoiseStream({ audio: true, video: true }); + self.audioTrack = stream.getAudioTracks()[0]; + self.videoTrack = stream.getVideoTracks()[0]; + } +); |