diff options
Diffstat (limited to 'testing/web-platform/tests/webrtc/legacy')
6 files changed, 801 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/legacy/README.txt b/testing/web-platform/tests/webrtc/legacy/README.txt new file mode 100644 index 0000000000..8adbf6aa17 --- /dev/null +++ b/testing/web-platform/tests/webrtc/legacy/README.txt @@ -0,0 +1,2 @@ +This directory contains files that test for behavior relevant to webrtc, +particularly defined in https://w3c.github.io/webrtc-pc/#legacy-interface-extensions diff --git a/testing/web-platform/tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html b/testing/web-platform/tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html new file mode 100644 index 0000000000..f710498e75 --- /dev/null +++ b/testing/web-platform/tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html @@ -0,0 +1,274 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test legacy offerToReceiveAudio/Video options</title> +<link rel="help" href="https://w3c.github.io/webrtc-pc/#legacy-configuration-extensions"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../RTCPeerConnection-helper.js"></script> +<script> + 'use strict'; + + /* + * 4.3.3.2 Configuration data extensions + * partial dictionary RTCOfferOptions + */ + + /* + * offerToReceiveAudio of type boolean + * When this is given a non-false value, no outgoing track of type + * "audio" is attached to the PeerConnection, and the existing + * localDescription (if any) doesn't contain any sendrecv or recv + * audio media sections, createOffer() will behave as if + * addTransceiver("audio") had been called once prior to the createOffer() call. + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return pc.createOffer({ offerToReceiveAudio: true }) + .then(offer1 => { + assert_equals(countAudioLine(offer1.sdp), 1, + 'Expect created offer to have audio line'); + + // The first createOffer implicitly calls addTransceiver('audio'), + // so all following offers will also have audio media section + // in their SDP. + return pc.createOffer({ offerToReceiveAudio: false }) + .then(offer2 => { + assert_equals(countAudioLine(offer2.sdp), 1, + 'Expect audio line to remain in created offer'); + }) + }); + }, 'createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers'); + + /* + * offerToReceiveVideo of type boolean + * When this is given a non-false value, and no outgoing track + * of type "video" is attached to the PeerConnection, and the + * existing localDescription (if any) doesn't contain any sendecv + * or recv video media sections, createOffer() will behave as if + * addTransceiver("video") had been called prior to the createOffer() call. + */ + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return pc.createOffer({ offerToReceiveVideo: true }) + .then(offer1 => { + assert_equals(countVideoLine(offer1.sdp), 1, + 'Expect created offer to have video line'); + + return pc.createOffer({ offerToReceiveVideo: false }) + .then(offer2 => { + assert_equals(countVideoLine(offer2.sdp), 1, + 'Expect video line to remain in created offer'); + }) + }); + }, 'createOffer() with offerToReceiveVideo should add video line to all subsequent created offers'); + + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return pc.createOffer({ + offerToReceiveAudio: true, + offerToReceiveVideo: false + }).then(offer1 => { + assert_equals(countAudioLine(offer1.sdp), 1, + 'Expect audio line to be found in created offer'); + + assert_equals(countVideoLine(offer1.sdp), 0, + 'Expect video line to not be found in create offer'); + + return pc.createOffer({ + offerToReceiveAudio: false, + offerToReceiveVideo: true + }).then(offer2 => { + assert_equals(countAudioLine(offer2.sdp), 1, + 'Expect audio line to remain in created offer'); + + assert_equals(countVideoLine(offer2.sdp), 1, + 'Expect video line to be found in create offer'); + }) + }); + }, 'createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line'); + + + // Run some tests for both audio and video kinds + ['audio', 'video'].forEach((kind) => { + const capsKind = kind[0].toUpperCase() + kind.slice(1); + + const offerToReceiveTrue = {}; + offerToReceiveTrue[`offerToReceive${capsKind}`] = true; + + const offerToReceiveFalse = {}; + offerToReceiveFalse[`offerToReceive${capsKind}`] = false; + + // Start testing + promise_test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const dummy = pc.createDataChannel('foo'); // Just to have something to offer + + return pc.createOffer(offerToReceiveFalse) + .then(() => { + assert_equals(pc.getTransceivers().length, 0, + 'Expect pc to have no transceivers'); + }); + }, `createOffer() with offerToReceive${capsKind} set to false should not create a transceiver`); + + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return pc.createOffer(offerToReceiveTrue) + .then(() => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to have one transceiver'); + + const transceiver = pc.getTransceivers()[0]; + assert_equals(transceiver.direction, 'recvonly', + 'Expect transceiver to have "recvonly" direction'); + }); + }, `createOffer() with offerToReceive${capsKind} should create a "recvonly" transceiver`); + + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return pc.createOffer(offerToReceiveTrue) + .then(() => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to have one transceiver'); + + const transceiver = pc.getTransceivers()[0]; + assert_equals(transceiver.direction, 'recvonly', + 'Expect transceiver to have "recvonly" direction'); + }) + .then(() => pc.createOffer(offerToReceiveTrue)) + .then(() => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to still have only one transceiver'); + }) + ; + }, `offerToReceive${capsKind} option should be ignored if a non-stopped "recvonly" transceiver exists`); + + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return getTrackFromUserMedia(kind) + .then(([track, stream]) => { + pc.addTrack(track, stream); + return pc.createOffer(); + }) + .then(() => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to have one transceiver'); + + const transceiver = pc.getTransceivers()[0]; + assert_equals(transceiver.direction, 'sendrecv', + 'Expect transceiver to have "sendrecv" direction'); + }) + .then(() => pc.createOffer(offerToReceiveTrue)) + .then(() => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to still have only one transceiver'); + }) + ; + }, `offerToReceive${capsKind} option should be ignored if a non-stopped "sendrecv" transceiver exists`); + + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return getTrackFromUserMedia(kind) + .then(([track, stream]) => { + pc.addTrack(track, stream); + return pc.createOffer(offerToReceiveFalse); + }) + .then(() => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to have one transceiver'); + + const transceiver = pc.getTransceivers()[0]; + assert_equals(transceiver.direction, 'sendonly', + 'Expect transceiver to have "sendonly" direction'); + }) + ; + }, `offerToReceive${capsKind} set to false with a track should create a "sendonly" transceiver`); + + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + pc.addTransceiver(kind, {direction: 'recvonly'}); + + return pc.createOffer(offerToReceiveFalse) + .then(() => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to have one transceiver'); + + const transceiver = pc.getTransceivers()[0]; + assert_equals(transceiver.direction, 'inactive', + 'Expect transceiver to have "inactive" direction'); + }) + ; + }, `offerToReceive${capsKind} set to false with a "recvonly" transceiver should change the direction to "inactive"`); + + promise_test(t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const pc2 = new RTCPeerConnection(); + + t.add_cleanup(() => pc2.close()); + + return getTrackFromUserMedia(kind) + .then(([track, stream]) => { + pc.addTrack(track, stream); + return pc.createOffer(); + }) + .then((offer) => pc.setLocalDescription(offer)) + .then(() => pc2.setRemoteDescription(pc.localDescription)) + .then(() => pc2.createAnswer()) + .then((answer) => pc2.setLocalDescription(answer)) + .then(() => pc.setRemoteDescription(pc2.localDescription)) + .then(() => pc.createOffer(offerToReceiveFalse)) + .then((offer) => { + assert_equals(pc.getTransceivers().length, 1, + 'Expect pc to have one transceiver'); + + const transceiver = pc.getTransceivers()[0]; + assert_equals(transceiver.direction, 'sendonly', + 'Expect transceiver to have "sendonly" direction'); + }) + ; + }, `subsequent offerToReceive${capsKind} set to false with a track should change the direction to "sendonly"`); + }); + + promise_test(t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + return pc.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true }) + .then(() => { + assert_equals(pc.getTransceivers().length, 2, + 'Expect pc to have two transceivers'); + + assert_equals(pc.getTransceivers()[0].direction, 'recvonly', + 'Expect first transceiver to have "recvonly" direction'); + assert_equals(pc.getTransceivers()[1].direction, 'recvonly', + 'Expect second transceiver to have "recvonly" direction'); + }); + }, 'offerToReceiveAudio and Video should create two "recvonly" transceivers'); + +</script> diff --git a/testing/web-platform/tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html b/testing/web-platform/tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html new file mode 100644 index 0000000000..65a4d7e393 --- /dev/null +++ b/testing/web-platform/tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html @@ -0,0 +1,172 @@ +<!doctype html> +<meta charset=utf-8> +<title>RTCRtpTransceiver with OfferToReceive legacy options</title> +<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="../RTCPeerConnection-helper.js"></script> +<script> + 'use strict'; + + const stopTracks = (...streams) => { + streams.forEach(stream => stream.getTracks().forEach(track => track.stop())); + }; + + // comparable() - produces copy of object that is JSON comparable. + // o = original object (required) + // t = template of what to examine. Useful if o is non-enumerable (optional) + + const comparable = (o, t = o) => { + if (typeof o != 'object' || !o) { + return o; + } + if (Array.isArray(t) && Array.isArray(o)) { + return o.map((n, i) => comparable(n, t[i])); + } + return Object.keys(t).sort() + .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {}); + }; + + const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:"); + + const hasProps = (observed, expected) => { + const observable = comparable(observed, expected); + assert_equals(stripKeyQuotes(JSON.stringify(observable)), + stripKeyQuotes(JSON.stringify(comparable(expected)))); + }; + + const checkAddTransceiverWithStream = async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + await setMediaPermission(); + const audioStream = await navigator.mediaDevices.getUserMedia({audio: true}); + const videoStream = await navigator.mediaDevices.getUserMedia({video: true}); + t.add_cleanup(() => stopTracks(audioStream, videoStream)); + + const audio = audioStream.getAudioTracks()[0]; + const video = videoStream.getVideoTracks()[0]; + + pc.addTransceiver(audio, {streams: [audioStream]}); + pc.addTransceiver(video, {streams: [videoStream]}); + + hasProps(pc.getTransceivers(), + [ + { + receiver: {track: {kind: "audio"}}, + sender: {track: audio}, + direction: "sendrecv", + mid: null, + currentDirection: null, + stopped: false + }, + { + receiver: {track: {kind: "video"}}, + sender: {track: video}, + direction: "sendrecv", + mid: null, + currentDirection: null, + stopped: false + } + ]); + + const offer = await pc.createOffer(); + assert_true(offer.sdp.includes("a=msid:" + audioStream.id), + "offer contains the expected audio msid"); + assert_true(offer.sdp.includes("a=msid:" + videoStream.id), + "offer contains the expected video msid"); + }; + + const checkAddTransceiverWithOfferToReceive = async (t, kinds) => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + + const propsToSet = kinds.map(kind => { + if (kind == "audio") { + return "offerToReceiveAudio"; + } else if (kind == "video") { + return "offerToReceiveVideo"; + } + }); + + const options = {}; + + for (const prop of propsToSet) { + options[prop] = true; + } + + let offer = await pc.createOffer(options); + + const expected = []; + + if (options.offerToReceiveAudio) { + expected.push( + { + receiver: {track: {kind: "audio"}}, + sender: {track: null}, + direction: "recvonly", + mid: null, + currentDirection: null, + stopped: false + }); + } + + if (options.offerToReceiveVideo) { + expected.push( + { + receiver: {track: {kind: "video"}}, + sender: {track: null}, + direction: "recvonly", + mid: null, + currentDirection: null, + stopped: false + }); + } + + hasProps(pc.getTransceivers(), expected); + + // Test offerToReceive: false + for (const prop of propsToSet) { + options[prop] = false; + } + + // Check that sendrecv goes to sendonly + for (const transceiver of pc.getTransceivers()) { + transceiver.direction = "sendrecv"; + } + + for (const transceiverCheck of expected) { + transceiverCheck.direction = "sendonly"; + } + + offer = await pc.createOffer(options); + hasProps(pc.getTransceivers(), expected); + + // Check that recvonly goes to inactive + for (const transceiver of pc.getTransceivers()) { + transceiver.direction = "recvonly"; + } + + for (const transceiverCheck of expected) { + transceiverCheck.direction = "inactive"; + } + + offer = await pc.createOffer(options); + hasProps(pc.getTransceivers(), expected); + }; + +const tests = [ + checkAddTransceiverWithStream, + function checkAddTransceiverWithOfferToReceiveAudio(t) { + return checkAddTransceiverWithOfferToReceive(t, ["audio"]); + }, + function checkAddTransceiverWithOfferToReceiveVideo(t) { + return checkAddTransceiverWithOfferToReceive(t, ["video"]); + }, + function checkAddTransceiverWithOfferToReceiveBoth(t) { + return checkAddTransceiverWithOfferToReceive(t, ["audio", "video"]); + } +].forEach(test => promise_test(test, test.name)); + +</script> diff --git a/testing/web-platform/tests/webrtc/legacy/munge-dont.html b/testing/web-platform/tests/webrtc/legacy/munge-dont.html new file mode 100644 index 0000000000..b5f0a4cb63 --- /dev/null +++ b/testing/web-platform/tests/webrtc/legacy/munge-dont.html @@ -0,0 +1,88 @@ +<!doctype html> +<meta charset=utf-8> +<meta name="timeout" content="long"> +<title>SDP munging is a bad idea</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +'use strict'; + +const sdp = `v=0 +o=- 0 3 IN IP4 127.0.0.1 +s=- +t=0 0 +m=video 9 UDP/TLS/RTP/SAVPF 100 +c=IN IP4 0.0.0.0 +a=rtcp-mux +a=sendonly +a=mid:video +a=rtpmap:100 VP8/90000 +a=fmtp:100 max-fr=30;max-fs=3600 +a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93 +a=ice-ufrag:ETEn +a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l +`; +const candidateString = 'candidate:1905690388 1 udp 2113937151 192.168.0.1 58041 typ host generation 0 ufrag thC8'; + +// See https://bugs.chromium.org/p/chromium/issues/detail?id=662898 +// and https://bugs.chromium.org/p/chromium/issues/detail?id=823036 +// for why neither of these is feasible to enforce. + +// Note that this does not restrict creating a +// new RTCSessionDescription with a modified copy. +test(() => { + const desc = new RTCSessionDescription({ + type: 'offer', + sdp, + }); + assert_throws_js(TypeError, () => { + desc.type = 'answer'; + }); +}, 'RTCSessionDescription.type is read-only'); + +test(() => { + const desc = new RTCSessionDescription({ + type: 'offer', + sdp, + }); + assert_throws_js(TypeError, () => { + desc.sdp += 'a=dont-modify-me\r\n'; + }); +}, 'RTCSessionDescription.sdp is read-only'); + +test(() => { + const candidate = new RTCIceCandidate({ + sdpMid: '0', + candidate: candidateString, + }); + assert_throws_js(TypeError, () => { + candidate.candidate += ' myattribute value'; + }); +}, 'RTCIceCandidate.candidate is read-only'); + +// https://w3c.github.io/webrtc-pc/#dom-peerconnection-setlocaldescription +// If type is "offer", and sdp is not the empty string and not equal to +// connection.[[LastCreatedOffer]], then return a promise rejected with a +// newly created InvalidModificationError and abort these steps. +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + pc.addTransceiver('audio'); + const offer = await pc.createOffer(); + return promise_rejects_dom(t, 'InvalidModificationError', + pc.setLocalDescription({type: 'offer', sdp: offer.sdp + 'a=munging-is-not-good\r\n'})); +}, 'Rejects SDP munging between createOffer and setLocalDescription'); + +// If type is "answer" or "pranswer", and sdp is not the empty string and not equal to +// connection.[[LastCreatedAnswer]], then return a promise rejected with a +// newly created InvalidModificationError and abort these steps. +promise_test(async t => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + await pc.setRemoteDescription({type: 'offer', sdp}); + + const answer = await pc.createAnswer(); + return promise_rejects_dom(t, 'InvalidModificationError', + pc.setLocalDescription({type: 'answer', sdp: answer.sdp + 'a=munging-is-not-good\r\n'})); +}, 'Rejects SDP munging between createAnswer and setLocalDescription'); +</script> diff --git a/testing/web-platform/tests/webrtc/legacy/onaddstream.https.html b/testing/web-platform/tests/webrtc/legacy/onaddstream.https.html new file mode 100644 index 0000000000..b5e8a402b8 --- /dev/null +++ b/testing/web-platform/tests/webrtc/legacy/onaddstream.https.html @@ -0,0 +1,157 @@ +<!doctype html> +<meta charset=utf-8> +<title>onaddstream tests</title> +<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> + 'use strict'; + + const stopTracks = (...streams) => { + streams.forEach(stream => stream.getTracks().forEach(track => track.stop())); + }; + + const collectEvents = (target, name, check) => { + const events = []; + const handler = e => { + check(e); + events.push(e); + }; + + target.addEventListener(name, handler); + + const finishCollecting = () => { + target.removeEventListener(name, handler); + return events; + }; + + return {finish: finishCollecting}; + }; + + const collectAddTrackEvents = stream => { + const checkEvent = e => { + assert_true(e.track instanceof MediaStreamTrack, "Track is set on event"); + assert_true(stream.getTracks().includes(e.track), + "track in addtrack event is in the stream"); + }; + return collectEvents(stream, "addtrack", checkEvent); + }; + + const collectRemoveTrackEvents = stream => { + const checkEvent = e => { + assert_true(e.track instanceof MediaStreamTrack, "Track is set on event"); + assert_true(!stream.getTracks().includes(e.track), + "track in removetrack event is not in the stream"); + }; + return collectEvents(stream, "removetrack", checkEvent); + }; + + const collectTrackEvents = pc => { + const checkEvent = e => { + assert_true(e.track instanceof MediaStreamTrack, "Track is set on event"); + assert_true(e.receiver instanceof RTCRtpReceiver, "Receiver is set on event"); + assert_true(e.transceiver instanceof RTCRtpTransceiver, "Transceiver is set on event"); + assert_true(Array.isArray(e.streams), "Streams is set on event"); + e.streams.forEach(stream => { + assert_true(stream.getTracks().includes(e.track), + "Each stream in event contains the track"); + }); + assert_equals(e.receiver, e.transceiver.receiver, + "Receiver belongs to transceiver"); + assert_equals(e.track, e.receiver.track, + "Track belongs to receiver"); + }; + + return collectEvents(pc, "track", checkEvent); + }; + + // comparable() - produces copy of object that is JSON comparable. + // o = original object (required) + // t = template of what to examine. Useful if o is non-enumerable (optional) + + const comparable = (o, t = o) => { + if (typeof o != 'object' || !o) { + return o; + } + if (Array.isArray(t) && Array.isArray(o)) { + return o.map((n, i) => comparable(n, t[i])); + } + return Object.keys(t).sort() + .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {}); + }; + + const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:"); + + const hasProps = (observed, expected) => { + const observable = comparable(observed, expected); + assert_equals(stripKeyQuotes(JSON.stringify(observable)), + stripKeyQuotes(JSON.stringify(comparable(expected)))); + }; + + promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + await setMediaPermission(); + const stream1 = await navigator.mediaDevices.getUserMedia({audio: true, video: true}); + t.add_cleanup(() => stopTracks(stream1)); + const audio1 = stream1.getAudioTracks()[0]; + pc1.addTrack(audio1, stream1); + const video1 = stream1.getVideoTracks()[0]; + pc1.addTrack(video1, stream1); + + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc2.close()); + const stream2 = await navigator.mediaDevices.getUserMedia({audio: true, video: true}); + t.add_cleanup(() => stopTracks(stream2)); + const audio2 = stream2.getAudioTracks()[0]; + pc2.addTrack(audio2, stream2); + const video2 = stream2.getVideoTracks()[0]; + pc2.addTrack(video2, stream2); + + const offer = await pc1.createOffer(); + + let trackEventCollector = collectTrackEvents(pc2); + let addstreamEventCollector = collectEvents(pc2, "addstream", e => { + hasProps(e, {stream: {id: stream1.id}}); + assert_equals(e.stream.getAudioTracks().length, 1, "One audio track"); + assert_equals(e.stream.getVideoTracks().length, 1, "One video track"); + }); + + await pc2.setRemoteDescription(offer); + + let addstreamEvents = addstreamEventCollector.finish(); + assert_equals(addstreamEvents.length, 1, "Should have 1 addstream event"); + + let trackEvents = trackEventCollector.finish(); + + hasProps(trackEvents, + [ + {streams: [addstreamEvents[0].stream]}, + {streams: [addstreamEvents[0].stream]} + ]); + + await pc1.setLocalDescription(offer); + const answer = await pc2.createAnswer(); + + trackEventCollector = collectTrackEvents(pc1); + addstreamEventCollector = collectEvents(pc1, "addstream", e => { + hasProps(e, {stream: {id: stream2.id}}); + assert_equals(e.stream.getAudioTracks().length, 1, "One audio track"); + assert_equals(e.stream.getVideoTracks().length, 1, "One video track"); + }); + + await pc1.setRemoteDescription(answer); + addstreamEvents = addstreamEventCollector.finish(); + assert_equals(addstreamEvents.length, 1, "Should have 1 addstream event"); + + trackEvents = trackEventCollector.finish(); + + hasProps(trackEvents, + [ + {streams: [addstreamEvents[0].stream]}, + {streams: [addstreamEvents[0].stream]} + ]); + },"Check onaddstream"); +</script> diff --git a/testing/web-platform/tests/webrtc/legacy/simplecall_callbacks.https.html b/testing/web-platform/tests/webrtc/legacy/simplecall_callbacks.https.html new file mode 100644 index 0000000000..f7b0ba7944 --- /dev/null +++ b/testing/web-platform/tests/webrtc/legacy/simplecall_callbacks.https.html @@ -0,0 +1,108 @@ +<!doctype html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title>RTCPeerConnection Connection Test</title> + <script src="../RTCPeerConnection-helper.js"></script> +</head> +<body> + <div id="log"></div> + <div> + <video id="local-view" muted autoplay="autoplay"></video> + <video id="remote-view" muted autoplay="autoplay"></video> + </div> + + <!-- These files are in place when executing on W3C. --> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script type="text/javascript"> + var test = async_test('Can set up a basic WebRTC call.'); + + var gFirstConnection = null; + var gSecondConnection = null; + + // if the remote video gets video data that implies the negotiation + // as well as the ICE and DTLS connection are up. + document.getElementById('remote-view') + .addEventListener('loadedmetadata', function() { + // Call negotiated: done. + test.done(); + }); + + function getNoiseStreamOkCallback(localStream) { + gFirstConnection = new RTCPeerConnection(null); + test.add_cleanup(() => gFirstConnection.close()); + gFirstConnection.onicecandidate = onIceCandidateToFirst; + localStream.getTracks().forEach(function(track) { + gFirstConnection.addTrack(track, localStream); + }); + gFirstConnection.createOffer(onOfferCreated, failed('createOffer')); + + var videoTag = document.getElementById('local-view'); + videoTag.srcObject = localStream; + }; + + var onOfferCreated = test.step_func(function(offer) { + gFirstConnection.setLocalDescription(offer); + + // This would normally go across the application's signaling solution. + // In our case, the "signaling" is to call this function. + receiveCall(offer.sdp); + }); + + function receiveCall(offerSdp) { + gSecondConnection = new RTCPeerConnection(null); + test.add_cleanup(() => gSecondConnection.close()); + gSecondConnection.onicecandidate = onIceCandidateToSecond; + gSecondConnection.ontrack = onRemoteTrack; + + var parsedOffer = new RTCSessionDescription({ type: 'offer', + sdp: offerSdp }); + gSecondConnection.setRemoteDescription(parsedOffer); + + gSecondConnection.createAnswer(onAnswerCreated, + failed('createAnswer')); + }; + + var onAnswerCreated = test.step_func(function(answer) { + gSecondConnection.setLocalDescription(answer); + + // Similarly, this would go over the application's signaling solution. + handleAnswer(answer.sdp); + }); + + function handleAnswer(answerSdp) { + var parsedAnswer = new RTCSessionDescription({ type: 'answer', + sdp: answerSdp }); + gFirstConnection.setRemoteDescription(parsedAnswer); + }; + + var onIceCandidateToFirst = test.step_func(function(event) { + gSecondConnection.addIceCandidate(event.candidate); + }); + + var onIceCandidateToSecond = test.step_func(function(event) { + gFirstConnection.addIceCandidate(event.candidate); + }); + + var onRemoteTrack = test.step_func(function(event) { + var videoTag = document.getElementById('remote-view'); + if (!videoTag.srcObject) { + videoTag.srcObject = event.streams[0]; + } + }); + + // Returns a suitable error callback. + function failed(function_name) { + return test.unreached_func('WebRTC called error callback for ' + function_name); + } + + // This function starts the test. + test.step(function() { + getNoiseStream({ video: true, audio: true }) + .then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream')); + }); +</script> + +</body> +</html> |