<!DOCTYPE html>
<!--
Take frames coming from OffscreenCanvas and send them over an RTCPeerConnection.
-->
<html>
<head>
<title>RTCPeerConnection test</title>
<script src="webcodecs_common.js"></script>
<script type="text/javascript">
'use strict';
async function main(arg) {
const use_worker = arg.use_worker;
const canvas = document.getElementById('display');
const ctx = canvas.getContext('2d');
const mst_generator = new MediaStreamTrackGenerator({kind: 'video'});
let stopSource = () => {};
if (use_worker) {
const worker = new Worker('webrtc-peer-connection-worker.js');
const writable = mst_generator.writable;
worker.postMessage(
{writable, width: canvas.width, height: canvas.height}, [writable]);
stopSource = () => {
worker.terminate();
};
} else {
const source = new CanvasSource(canvas.width, canvas.height);
const writer = mst_generator.writable.getWriter();
// write frames continuously until test is completed
const intervalId = setInterval(async () => {
await writer.write(await source.getNextFrame());
}, 100);
stopSource = () => {
clearInterval(intervalId);
source.close();
writer.close();
};
}
const pc_track = await startPeerConnectionPipe(mst_generator);
const mst_processor = new MediaStreamTrackProcessor({
track: pc_track,
});
const reader = mst_processor.readable.getReader();
// WebRTC starts with limited bandwidth, so the frames have large encoding
// artifacts. By 30 frames we expect the diff to be more reasonable,
// although the tolerance is still quite liberal.
const high_tolerance_frames_to_read = 30;
const low_tolerance_frames_to_read = 5;
for (let i = 0;
i < high_tolerance_frames_to_read + low_tolerance_frames_to_read;
i++) {
const {value: frame, done} = await reader.read();
if (done) {
TEST.reportFailure('stream ended unexpectedly');
}
ctx.drawImage(frame, 0, 0);
// TODO(crbug.com/40216940): These tolerances are very high.
// Colour space issue, or just an expected network encoding diff?
const tolerance = i < high_tolerance_frames_to_read ? 50 : 40;
checkFourColorsFrame(ctx, canvas.width, canvas.height, tolerance);
frame.close();
}
reader.cancel();
pc_track.stop();
}
/**
* Send a track over an RTCPeerConnection. In this case, both ends of the
* connection are local.
* @param {!MediaStreamTrack} inputTrack
* @return {!Promise<!MediaStreamTrack>}
*/
async function startPeerConnectionPipe(inputTrack) {
// Disable scaling to obtain stable results.
const caller = new RTCPeerConnection(null, {
optional: [
{
googCpuOveruseDetection: false,
},
],
});
const callee = new RTCPeerConnection(null);
caller.onicecandidate = (/** !RTCPeerConnectionIceEvent*/ event) => {
if (event.candidate) callee.addIceCandidate(event.candidate);
};
callee.onicecandidate = (/** !RTCPeerConnectionIceEvent */ event) => {
if (event.candidate) caller.addIceCandidate(event.candidate);
};
const outputTrackPromise = new Promise((resolve) => {
callee.ontrack = (/** !RTCTrackEvent */ event) => {
resolve(event.track);
};
});
caller.addTransceiver(inputTrack, {
direction: 'sendonly',
});
await caller.setLocalDescription();
await callee.setRemoteDescription(caller.localDescription);
await callee.setLocalDescription();
await caller.setRemoteDescription(callee.localDescription);
return await outputTrackPromise;
}
</script>
</head>
<body>
<div>
<canvas id='display' width="640" height="480"></canvas>
</div>
</body>
</html>