Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /webrtc-encoded-transform/RTCRtpScriptTransform-encoded-transform.https.html - WPT Dashboard Interop Dashboard
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=/resources/testdriver.js></script>
<script src=/resources/testdriver-vendor.js></script>
<script src='../mediacapture-streams/permission-helper.js'></script>
<script src="/webrtc/RTCPeerConnection-helper.js"></script>
<script src ="routines.js"></script>
</head>
<body>
<video id="video" autoplay controls playsinline></video>
<script>
promise_test(async (test) => {
const worker = new Worker('RTCRtpScriptTransform-encoded-transform-worker.js');
let sender, receiver;
const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender'});
const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver'});
const pc = new RTCPeerConnection();
const transceiver1 = pc.addTransceiver("audio");
const transceiver2 = pc.addTransceiver("audio");
transceiver1.sender.transform = senderTransform;
transceiver1.receiver.transform = receiverTransform;
transceiver1.sender.transform = senderTransform;
transceiver1.receiver.transform = receiverTransform;
assert_throws_dom("InvalidStateError", () => transceiver2.sender.transform = senderTransform, "set a used transform 1");
assert_throws_dom("InvalidStateError", () => transceiver2.receiver.transform = receiverTransform, "set a used transform 2");
transceiver1.sender.transform = null;
transceiver1.receiver.transform = null;
assert_throws_dom("InvalidStateError", () => transceiver2.sender.transform = senderTransform, "set a used transform 3");
assert_throws_dom("InvalidStateError", () => transceiver2.receiver.transform = receiverTransform, "set a used transform 4");
}, "Once a transform has been attached, it cannot be reused elsewhere.");
promise_test(async (test) => {
const worker = new Worker('RTCRtpScriptTransform-encoded-transform-worker.js');
const data = await new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
assert_equals(data, "registered");
await setMediaPermission("granted", ["camera"]);
const localStream = await navigator.mediaDevices.getUserMedia({video: true});
let sender, receiver;
const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender'});
const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver'});
const stream = await new Promise((resolve, reject) => {
createConnections(test, (firstConnection) => {
sender = firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
sender.transform = senderTransform;
}, (secondConnection) => {
secondConnection.ontrack = (trackEvent) => {
receiver = trackEvent.receiver;
receiver.transform = receiverTransform;
resolve(trackEvent.streams[0]);
};
});
});
video.srcObject = stream;
const playingPromise = new Promise(r => video.onplaying = r);
await video.play();
const updatePromise = new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
assert_equals(await updatePromise, "got expected");
await playingPromise;
}, "Receiver and sender read, modifiy and write video frames.");
promise_test(async (test) => {
const worker = new Worker('RTCRtpScriptTransform-encoded-transform-worker.js');
const data = await new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
assert_equals(data, "registered");
await setMediaPermission("granted", ["microphone"]);
const localStream = await navigator.mediaDevices.getUserMedia({audio: true});
let sender, receiver;
const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender'});
const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver'});
const stream = await new Promise((resolve, reject) => {
createConnections(test, (firstConnection) => {
sender = firstConnection.addTrack(localStream.getAudioTracks()[0], localStream);
sender.transform = senderTransform;
}, (secondConnection) => {
secondConnection.ontrack = (trackEvent) => {
receiver = trackEvent.receiver;
receiver.transform = receiverTransform;
resolve(trackEvent.streams[0]);
};
});
});
video.srcObject = stream;
const playingPromise = new Promise(r => video.onplaying = r);
await video.play();
const updatePromise = new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
assert_equals(await updatePromise, "got expected");
await playingPromise;
}, "Receiver and sender read, modifiy and write audio frames.");
promise_test(async (test) => {
const worker = new Worker('RTCRtpScriptTransform-encoded-transform-no-write-worker.js');
const data = await new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
assert_equals(data, "registered");
await setMediaPermission("granted", ["camera"]);
const localStream = await navigator.mediaDevices.getUserMedia({video: true});
let sender, receiver;
const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender'});
const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver'});
const stream = await new Promise((resolve, reject) => {
createConnections(test, (firstConnection) => {
sender = firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
sender.transform = senderTransform;
}, (secondConnection) => {
secondConnection.ontrack = (trackEvent) => {
receiver = trackEvent.receiver;
receiver.transform = receiverTransform;
resolve(trackEvent.streams[0]);
};
});
});
video.srcObject = stream;
// As the receiver doesn't get any frames, it won't post a success
// message back and it will cause an expected timeout.
return new Promise((resolve, reject) => {
worker.onmessage = (event) => {reject()};
test.step_timeout(resolve, 500);
});
}, "Sender reads frames but doesn't write them back. Receiver doesn't receive any frames.");
promise_test(async (test) => {
const worker = new Worker('RTCRtpScriptTransform-encoded-transform-drop-frames-worker.js');
const data = await new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
assert_equals(data, "registered");
await setMediaPermission("granted", ["camera"]);
const localStream = await navigator.mediaDevices.getUserMedia({video: true});
let sender, receiver;
const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender'});
const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver'});
const stream = await new Promise((resolve, reject) => {
createConnections(test, (firstConnection) => {
sender = firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
sender.transform = senderTransform;
}, (secondConnection) => {
secondConnection.ontrack = (trackEvent) => {
receiver = trackEvent.receiver;
receiver.transform = receiverTransform;
resolve(trackEvent.streams[0]);
};
});
});
video.srcObject = stream;
const updatePromise = new Promise(resolve => worker.onmessage = (event) => resolve(event.data));
assert_equals(await updatePromise, "got expected");
}, "Sender skips some frames and only writes one back. Receiver only receives that frame.");
["audio", "video"].forEach(kind => {
["inplace", "detach", "overwrite", "clone-frame"].forEach(mode => {
promise_test(async (test) => {
const worker = await createWorker('RTCRtpScriptTransform-encoded-transform-flex-worker.js');
const localStream = await getNoiseStream({[kind]: true});
let sender, receiver;
const senderTransform = new RTCRtpScriptTransform(worker, {name:'sender', mode});
const receiverTransform = new RTCRtpScriptTransform(worker, {name:'receiver', mode});
const stream = await new Promise((resolve, reject) => {
createConnections(test, (firstConnection) => {
sender = firstConnection.addTrack(localStream.getTracks()[0], localStream);
sender.transform = senderTransform;
}, (secondConnection) => {
secondConnection.ontrack = (trackEvent) => {
receiver = trackEvent.receiver;
receiver.transform = receiverTransform;
resolve(trackEvent.streams[0]);
};
});
});
assert_equals(await nextMessageOrTimeout(test, worker, 1000),
"sender written");
if (mode == "detach") {
// Debatable? What does spec say?
assert_equals(await nextMessageOrTimeout(test, worker, 1000),
undefined,
"If worker detaches the frame, no frame should be received");
} else {
assert_equals(await nextMessageOrTimeout(test, worker, 1000),
"receiver written");
}
}, `Receiver and sender read/write frames (${mode}, ${kind}).`);
});
});
</script>
</body>
</html>