tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4c90575bfc410a0868a1966bb2bd1920f3809dca
parent 3915f574e791c4e627094c5a855da91714faa1ec
Author: Nico Grunbaum <na-g@nostrum.com>
Date:   Thu,  2 Oct 2025 18:59:52 +0000

Bug 1988565 - additional outbound-rtp stat lifetime WPTs;r=jib

Differential Revision: https://phabricator.services.mozilla.com/D264893

Diffstat:
Mtesting/web-platform/tests/webrtc/rtp-stats-lifetime.https.html | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 75 insertions(+), 4 deletions(-)

diff --git a/testing/web-platform/tests/webrtc/rtp-stats-lifetime.https.html b/testing/web-platform/tests/webrtc/rtp-stats-lifetime.https.html @@ -19,12 +19,12 @@ async function hasStats(pc, type) { return false; } -async function getInboundRtpPollUntilItExists(pc, kTimeoutMs = 10000) { +async function getStatsTypePollUntilItExists(pc, type, kTimeoutMs = 10000) { const t0 = performance.now(); while (performance.now() - t0 < kTimeoutMs) { const report = await pc.getStats(); for (const stats of report.values()) { - if (stats.type == 'inbound-rtp') { + if (stats.type == type) { return stats; } } @@ -118,7 +118,7 @@ promise_test(async t => { const [track] = stream.getTracks(); t.add_cleanup(() => track.stop()); await sender.replaceTrack(track); - const inboundRtp = await getInboundRtpPollUntilItExists(pc2); + const inboundRtp = await getStatsTypePollUntilItExists(pc2, 'inbound-rtp'); assert_not_equals( inboundRtp, null, 'inbound-rtp should be created in response to the sender having a track'); @@ -127,6 +127,77 @@ promise_test(async t => { 'inbound-rtp must only exist after packets have been received'); }, `RTCInboundRtpStreamStats are created by packet reception`); +[{name: "pc", statsSource: pc => pc, kind: "audio"}, + {name: "sender", statsSource: pc => pc.getSenders()[0], kind: "audio"}, + {name: "pc", statsSource: pc => pc, kind: "video"}, + {name: "sender", statsSource: pc => pc.getSenders()[0], kind: "video"} +].forEach(({name, statsSource, kind}) => promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate); + pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate); + + // Check statsSource for the outbound-rtp stats object. + const getOutboundRtpStats = async () => + await getStatsTypePollUntilItExists(statsSource(pc1), 'outbound-rtp'); + + pc1.addTransceiver(kind); + await pc1.setLocalDescription(); + await pc2.setRemoteDescription(pc1.localDescription); + await pc2.setLocalDescription(); + await pc1.setRemoteDescription(pc2.localDescription); + + { + const stats = await getOutboundRtpStats(); + assert_not_equals( + stats, null, + `outbound-rtp should be created in ${name}.getStats() in response to the pc.addTransceiver("${kind}")`); + } +}, `RTCOutboundRtpStreamStats exist in ${name}.getStats() after created with a null track through pc.addTransceiver("${kind}")`)); + +[{name: "pc", statsSource: pc => pc}, + {name: "sender", statsSource: pc => pc.getSenders()[0]} +].forEach(({name, statsSource}) => promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate); + pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate); + + // Check statsSource for the outbound-rtp stats object. + const getOutboundRtpStats = async () => + await getStatsTypePollUntilItExists(statsSource(pc1), 'outbound-rtp'); + + const stream = await getNoiseStream({video:true}); + + const {sender} = pc1.addTransceiver(stream.getTracks()[0]); + await pc1.setLocalDescription(); + await pc2.setRemoteDescription(pc1.localDescription); + await pc2.setLocalDescription(); + await pc1.setRemoteDescription(pc2.localDescription); + + // Wait for packets to be received + { + const stats = await getOutboundRtpStats(); + assert_not_equals( + stats, null, + `outbound-rtp should be created in ${name}.getStats() in response to the sender having a track`); + } + + // Stop sending. This should not remove the outbound-rtp stats object. + await sender.replaceTrack(null); + // Check that the outbound-rtp stats object remains. + { + const stats = await getOutboundRtpStats(); + assert_not_equals( + stats, null, + `outbound-rtp should remain in ${name}.getStats() after sender.replaceTrack(null)`); + } +}, `RTCOutboundRtpStreamStats remain in ${name}.getStats() after sender.replaceTrack(null)`)); + promise_test(async t => { const pc1 = new RTCPeerConnection(); t.add_cleanup(() => pc1.close()); @@ -164,7 +235,7 @@ promise_test(async t => { // But because of early media, we're still able to receive packets. // - Whether or not we unmute the track in response to this is outside the // scope of this test. - const inboundRtp = await getInboundRtpPollUntilItExists(pc1); + const inboundRtp = await getStatsTypePollUntilItExists(pc1, 'inbound-rtp'); assert_not_equals( inboundRtp, null, 'inbound-rtp should be created in the early media use case');