| <!doctype html> | |
| <meta charset=utf-8> | |
| <title>onaddstream tests</title> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.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()); | |
| 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> |