Update web-platform-tests to revision be5419e845d39089ba6dc338c1bd0fa279108317

This commit is contained in:
Josh Matthews 2018-01-04 13:44:24 -05:00
parent aa199307c8
commit 2b6f573eb5
3440 changed files with 109438 additions and 41750 deletions

View file

@ -1,3 +1,4 @@
@snuggs
@agouaillard
@alvestrand
@dontcallmedom

View file

@ -172,8 +172,9 @@
assert_equals(typeof fingerprint, 'object',
'Expect fingerprint to be an object (dictionary)');
// Can only do simple test as the allowed values may be extended
assert_true(/^[a-zA-Z\-]+$/.test(fingerprint.algorithm),
// https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml
const algorithms = ['md2', 'md5', 'sha-1', 'sha-224', 'sha-256', 'sha-384', 'sha-512'];
assert_in_array(fingerprint.algorithm, algorithms,
'Expect fingerprint.algorithm to be string of algorithm identifier');
assert_true(/^([0-9a-f]{2}\:)+[0-9a-f]{2}$/.test(fingerprint.value),

View file

@ -64,7 +64,7 @@
assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
pc.setConfiguration({ iceTransportPolicy: 'relay' });
assert_equals(pc.getConfiguration(), iceTransportPolicy, 'relay');
assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
}, `setConfiguration({ iceTransportPolicy: 'relay' }) with initial iceTransportPolicy all should succeed`);
test(() => {
@ -72,7 +72,7 @@
assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
pc.setConfiguration({ iceTransportPolicy: 'all' });
assert_equals(pc.getConfiguration(), iceTransportPolicy, 'all');
assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
}, `setConfiguration({ iceTransportPolicy: 'all' }) with initial iceTransportPolicy relay should succeed`);
test(() => {
@ -81,7 +81,7 @@
// default value for iceTransportPolicy is all
pc.setConfiguration({});
assert_equals(pc.getConfiguration(), iceTransportPolicy, 'all');
assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
}, `setConfiguration({}) with initial iceTransportPolicy relay should set new value to all`);
config_test(makePc => {

View file

@ -76,8 +76,8 @@ function test_tone_change_events(testFunc, toneChanges, desc) {
const now = Date.now();
const duration = now - lastEventTime;
assert_approx_equals(duration, expectedDuration, 150,
`Expect tonechange event for "${tone}" to be fired approximately after ${expectedDuration} seconds`);
assert_approx_equals(duration, expectedDuration, 250,
`Expect tonechange event for "${tone}" to be fired approximately after ${expectedDuration} milliseconds`);
lastEventTime = now;

View file

@ -76,7 +76,7 @@
testedTransports.add(dtlsTransport);
// End the test if both dtlsTransports are tested.
if(testedTransports.has(dtlsTransport1) && testedTransports.has(dtslTransport2)) {
if(testedTransports.has(dtlsTransport1) && testedTransports.has(dtlsTransport2)) {
t.done();
}
})

View file

@ -80,6 +80,8 @@
*/
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_idl_attribute(pc, 'addTransceiver');
assert_throws(new TypeError(), () => pc.addTransceiver('invalid'));
}, 'addTransceiver() with string argument as invalid kind should throw TypeError');
@ -125,6 +127,7 @@
*/
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_idl_attribute(pc, 'addTransceiver');
@ -170,6 +173,7 @@
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_idl_attribute(pc, 'addTransceiver');
@ -214,18 +218,24 @@
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' });
assert_equals(transceiver.direction, 'sendonly');
}, `addTransceiver() with direction sendonly should have result transceiver.direction be the same`);
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
const transceiver = pc.addTransceiver('audio', { direction: 'inactive' });
assert_equals(transceiver.direction, 'inactive');
}, `addTransceiver() with direction inactive should have result transceiver.direction be the same`);
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_idl_attribute(pc, 'addTransceiver');
assert_throws(new TypeError(), () =>
pc.addTransceiver('audio', { direction: 'invalid' }));
@ -238,8 +248,9 @@
*/
test(t => {
const pc = new RTCPeerConnection();
const track = generateMediaStreamTrack('audio');
t.add_cleanup(() => pc.close());
const track = generateMediaStreamTrack('audio');
const transceiver = pc.addTransceiver(track);
const { sender, receiver } = transceiver;
@ -276,8 +287,9 @@
test(t => {
const pc = new RTCPeerConnection();
const track = generateMediaStreamTrack('audio');
t.add_cleanup(() => pc.close());
const track = generateMediaStreamTrack('audio');
const transceiver1 = pc.addTransceiver(track);
const transceiver2 = pc.addTransceiver(track);
@ -302,7 +314,6 @@
}, 'addTransceiver(track) multiple times should create multiple transceivers');
/*
5.1. addTransceiver
6. Verify that each rid value in sendEncodings is composed only of
@ -310,8 +321,9 @@
of 16 characters. If one of the RIDs does not meet these requirements,
throw a TypeError.
*/
test(() => {
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_idl_attribute(pc, 'addTransceiver');
assert_throws(new TypeError(), () =>
@ -322,8 +334,9 @@
}));
}, 'addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError');
test(() => {
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_idl_attribute(pc, 'addTransceiver');
assert_throws(new TypeError(), () =>
@ -334,8 +347,9 @@
}));
}, 'addTransceiver() with rid longer than 16 characters should throw TypeError');
test(() => {
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
pc.addTransceiver('audio', {
sendEncodings: [{
rid: 'foo'
@ -353,8 +367,9 @@
Aside from rid , all read-only parameters in the RTCRtpEncodingParameters
dictionaries, such as ssrc, must be left unset, or an error will be thrown.
*/
test(() => {
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_throws('InvalidAccessError', () =>
pc.addTransceiver('audio', {
@ -364,8 +379,9 @@
}));
}, `addTransceiver() with readonly ssrc set should throw InvalidAccessError`);
test(() => {
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_throws('InvalidAccessError', () =>
pc.addTransceiver('audio', {
@ -377,8 +393,9 @@
}));
}, `addTransceiver() with readonly rtx set should throw InvalidAccessError`);
test(() => {
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
assert_throws('InvalidAccessError', () =>
pc.addTransceiver('audio', {
@ -390,8 +407,10 @@
}));
}, `addTransceiver() with readonly fec set should throw InvalidAccessError`);
test(() => {
test(t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
pc.addTransceiver('audio', {
sendEncodings: [{
dtx: 'enabled',

View file

@ -73,7 +73,7 @@ for (const attr in initialState) {
if (!window.pc) {
window.pc = new RTCPeerConnection;
}
assert_equals(pc[attr], initialState[attr]);
assert_equals(window.pc[attr], initialState[attr]);
}, attr + ' initial value');
}
</script>

View file

@ -375,7 +375,7 @@ promise_test(t => {
assert_not_equals(channel1.id, null,
'Expect channel1.id to be assigned');
assert_greater_than_equals(channel1.id, 0,
assert_greater_than_equal(channel1.id, 0,
'Expect channel1.id to be set to valid unsigned short');
assert_less_than(channel1.id, 65535,
@ -386,7 +386,7 @@ promise_test(t => {
assert_not_equals(channel2.id, null,
'Expect channel2.id to be assigned');
assert_greater_than_equals(channel2.id, 0,
assert_greater_than_equal(channel2.id, 0,
'Expect channel2.id to be set to valid unsigned short');
assert_less_than(channel2.id, 65535,

View file

@ -0,0 +1,169 @@
<!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';
// 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();
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();
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();
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();
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();
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();
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();
const pc2 = new RTCPeerConnection();
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();
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>

View file

@ -10,8 +10,8 @@
'use strict';
// Test is based on the following editor draft:
// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
// https://w3c.github.io/webrtc-stats/archives/20170614/webrtc-stats.html
// webrtc-pc 20171130
// webrtc-stats 20171122
// The following helper function is called from RTCPeerConnection-helper.js
// getTrackFromUserMedia
@ -20,39 +20,25 @@
// validateStatsReport
// assert_stats_report_has_stats
// The following helper function is called from RTCPeerConnection-helper.js
// exchangeIceCandidates
// doSignalingHandshake
/*
8.2. RTCPeerConnection Interface Extensions
partial interface RTCPeerConnection {
Promise<RTCStatsReport> getStats(optional MediaStreamTrack? selector = null);
};
8.3. RTCStatsReport Object
interface RTCStatsReport {
readonly maplike<DOMString, object>;
};
8.4. RTCStats Dictionary
dictionary RTCStats {
DOMHighResTimeStamp timestamp;
RTCStatsType type;
DOMString id;
};
id
Two RTCStats objects, extracted from two different RTCStatsReport objects, MUST
have the same id if they were produced by inspecting the same underlying object.
8.2. getStats
1. Let selectorArg be the method's first argument.
2. Let connection be the RTCPeerConnection object on which the method was invoked.
3. If selectorArg is neither null nor a valid MediaStreamTrack, return a promise
rejected with a newly created TypeError.
3. If selectorArg is null, let selector be null.
4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender
or RTCRtpReceiver on connection which track member matches selectorArg.
If no such sender or receiver exists, or if more than one sender or
receiver fit this criteria, return a promise rejected with a newly
created InvalidAccessError.
5. Let p be a new promise.
6. Run the following steps in parallel:
1. Gather the stats indicated by selector according to the stats selection algorithm.
2. Resolve p with the resulting RTCStatsReport object, containing the gathered stats.
*/
promise_test(() => {
const pc = new RTCPeerConnection();
return pc.getStats();
@ -65,9 +51,11 @@
/*
8.2. getStats
4. Let selector be a RTCRtpSender or RTCRtpReceiver on connection which track
member matches selectorArg. If no such sender or receiver exists, return a promise
rejected with a newly created InvalidAccessError.
4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender
or RTCRtpReceiver on connection which track member matches selectorArg.
If no such sender or receiver exists, or if more than one sender or
receiver fit this criteria, return a promise rejected with a newly
created InvalidAccessError.
*/
promise_test(t => {
const pc = new RTCPeerConnection();
@ -94,12 +82,6 @@
return pc.getStats(track);
}, 'getStats() with track added via addTransceiver should succeed');
/*
8.2. getStats
4. Let selector be a RTCRtpSender or RTCRtpReceiver on connection which track
member matches selectorArg. If more than one sender or receiver fit this criteria,
return a promise rejected with a newly created InvalidAccessError.
*/
promise_test(t => {
const pc = new RTCPeerConnection();
return getTrackFromUserMedia('audio')
@ -140,7 +122,35 @@
validateStatsReport(statsReport);
assert_stats_report_has_stats(statsReport, ['peer-connection']);
});
}, 'getStats() with no argument should return stats report containing peer-connection stats');
}, 'getStats() with no argument should return stats report containing peer-connection stats on an empty PC');
promise_test(t => {
const pc = new RTCPeerConnection();
return getTrackFromUserMedia('audio')
.then(([track, mediaStream]) => {
pc.addTrack(track, mediaStream);
return pc.getStats();
})
.then(statsReport => {
validateStatsReport(statsReport);
assert_stats_report_has_stats(statsReport, ['peer-connection']);
assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
});
}, 'getStats() with no argument should return stats report containing peer-connection stats and outbound-track-stats');
promise_test(t => {
const pc = new RTCPeerConnection();
return getTrackFromUserMedia('audio')
.then(([track, mediaStream]) => {
pc.addTrack(track);
return pc.getStats();
})
.then(statsReport => {
validateStatsReport(statsReport);
assert_stats_report_has_stats(statsReport, ['peer-connection']);
assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
});
}, 'getStats() with no argument should return stats for no-stream tracks');
/*
8.5. The stats selection algorithm
@ -184,4 +194,150 @@
});
}, `getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats`);
/*
8.6 Mandatory To Implement Stats
An implementation MUST support generating statistics of the following types
when the corresponding objects exist on a PeerConnection, with the attributes
that are listed when they are valid for that object.
*/
const mandatoryStats = [
"codec",
"inbound-rtp",
"outbound-rtp",
"remote-inbound-rtp",
"remote-outbound-rtp",
"peer-connection",
"data-channel",
"stream",
"track",
"transport",
"candidate-pair",
"local-candidate",
"remote-candidate",
"certificate"
];
async_test(t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
const dataChannel = pc1.createDataChannel('test-channel');
return navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(t.step_func(mediaStream => {
const tracks = mediaStream.getTracks();
assert_equals(tracks.length, 2,
'Expect media stream to have one audio and one video track');
let audioTrack;
let videoTrack;
for (const track of tracks) {
t.add_cleanup(() => track.stop());
pc1.addTrack(track, mediaStream);
if (track.kind === 'audio') {
audioTrack = track;
} else if (track.kind === 'video') {
videoTrack = track;
}
}
if (!audioTrack || ! videoTrack) {
assert_unreached('Expect mediaStream to have both audio and video streams');
}
const testStatsReport = (pc, statsReport) => {
validateStatsReport(statsReport);
assert_stats_report_has_stats(statsReport, mandatoryStats);
const dataChannelStats = findStatsFromReport(statsReport,
stats => {
return stats.type === 'data-channel' &&
stats.dataChannelIdentifier === dataChannel.id;
},
'Expect data channel stats to be found');
assert_equals(dataChannelStats.label, 'test-channel');
const audioTrackStats = findStatsFromReport(statsReport,
stats => {
return stats.type === 'track' &&
stats.trackIdentifier === audioTrack.id;
},
'Expect audio track stats to be found');
assert_equals(audioTrackStats.kind, 'audio');
const videoTrackStats = findStatsFromReport(statsReport,
stats => {
return stats.type === 'track' &&
stats.trackIdentifier === videoTrack.id;
},
'Expect video track stats to be found');
assert_equals(videoTrackStats.kind, 'video');
const mediaStreamStats = findStatsFromReport(statsReport,
stats => {
return stats.type === 'stream' &&
stats.streamIdentifier === mediaStream.id;
},
'Expect media stream stats to be found');
assert_true(mediaStreamStats.trackIds.include(audioTrackStats.id));
assert_true(mediaStreamStats.trackIds.include(videoTrackStats.id));
}
const onConnected = t.step_func(() => {
// Wait a while for the peer connections to collect stats
t.step_timeout(() => {
Promise.all([
pc1.getStats()
.then(statsReport => testStatsReport(pc1, statsReport)),
pc2.getStats()
.then(statsReport => testStatsReport(pc2, statsReport))
])
.then(t.step_func_done())
.catch(t.step_func(err => {
assert_unreached(`test failed with error: ${err}`);
}));
}, 200)
})
let onTrackCount = 0
let onDataChannelCalled = false
pc2.addEventListener('track', t.step_func(() => {
onTrackCount++;
if (onTrackCount === 2 && onDataChannelCalled) {
onConnected();
}
}));
pc2.addEventListener('datachannel', t.step_func(() => {
onDataChannelCalled = true;
if (onTrackCount === 2) {
onConnected();
}
}));
exchangeIceCandidates(pc1, pc2);
doSignalingHandshake(pc1, pc2);
}))
.catch(t.step_func(err => {
assert_unreached(`test failed with error: ${err}`);
}));
}, `getStats() with connected peer connections having tracks and data channel should return all mandatory to implement stats`);
</script>

View file

@ -1,108 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>IDL check of RTCPeerConnection</title>
<link rel="author" title="Harald Alvestrand" href="mailto:hta@google.com"/>
<link rel="help" href="http://w3c.github.io/webrtc-pc/#rtcpeerconnection-interface">
</head>
<body>
<h1 class="instructions">Description</h1>
<p class="instructions">This test verifies the availability of the RTCPeerConnection interface.</p>
<div id='log'></div>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
<!-- The IDL is copied from the 22 September 2015 editors' draft. -->
<script type="text/plain">
[Constructor()]
interface EventTarget {
// Only a dummy definition is needed here.
};
[ Constructor (optional RTCConfiguration configuration)]
interface RTCPeerConnection : EventTarget {
Promise<RTCSessionDescription> createOffer (optional RTCOfferOptions options);
Promise<RTCSessionDescription> createAnswer (optional RTCAnswerOptions options);
Promise<void> setLocalDescription (RTCSessionDescription description);
readonly attribute RTCSessionDescription? localDescription;
readonly attribute RTCSessionDescription? currentLocalDescription;
readonly attribute RTCSessionDescription? pendingLocalDescription;
Promise<void> setRemoteDescription (RTCSessionDescription description);
readonly attribute RTCSessionDescription? remoteDescription;
readonly attribute RTCSessionDescription? currentRemoteDescription;
readonly attribute RTCSessionDescription? pendingRemoteDescription;
Promise<void> addIceCandidate (RTCIceCandidate candidate);
readonly attribute RTCSignalingState signalingState;
readonly attribute RTCIceGatheringState iceGatheringState;
readonly attribute RTCIceConnectionState iceConnectionState;
readonly attribute boolean? canTrickleIceCandidates;
RTCConfiguration getConfiguration ();
void setConfiguration (RTCConfiguration configuration);
void close ();
attribute EventHandler onnegotiationneeded;
attribute EventHandler onicecandidate;
attribute EventHandler onsignalingstatechange;
attribute EventHandler oniceconnectionstatechange;
attribute EventHandler onicegatheringstatechange;
};
partial interface RTCPeerConnection {
void createOffer (RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback, optional RTCOfferOptions options);
void setLocalDescription (RTCSessionDescription description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
void createAnswer (RTCSessionDescriptionCallback successCallback, RTCPeerConnectionErrorCallback failureCallback);
void setRemoteDescription (RTCSessionDescription description, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
void addIceCandidate (RTCIceCandidate candidate, VoidFunction successCallback, RTCPeerConnectionErrorCallback failureCallback);
void getStats (MediaStreamTrack? selector, RTCStatsCallback successCallback, RTCPeerConnectionErrorCallback failureCallback);
};
partial interface RTCPeerConnection {
static Promise<RTCCertificate> generateCertificate (AlgorithmIdentifier keygenAlgorithm);
};
partial interface RTCPeerConnection {
sequence<RTCRtpSender> getSenders ();
sequence<RTCRtpReceiver> getReceivers ();
RTCRtpSender addTrack (MediaStreamTrack track, MediaStream... streams);
void removeTrack (RTCRtpSender sender);
attribute EventHandler ontrack;
};
partial interface RTCPeerConnection {
RTCDataChannel createDataChannel ([TreatNullAs=EmptyString] DOMString label, optional RTCDataChannelInit dataChannelDict);
attribute EventHandler ondatachannel;
};
partial interface RTCPeerConnection {
readonly attribute RTCDTMFSender? dtmf;
};
partial interface RTCPeerConnection {
Promise<RTCStatsReport> getStats (optional MediaStreamTrack? selector);
};
partial interface RTCPeerConnection {
void setIdentityProvider (DOMString provider, optional DOMString protocol, optional DOMString usernameHint);
Promise<DOMString> getIdentityAssertion ();
readonly attribute Promise<RTCIdentityAssertion> peerIdentity;
readonly attribute DOMString? idpLoginUrl;
};
</script>
<script>
(function() {
var idl_array = new IdlArray();
[].forEach.call(document.querySelectorAll("script[type=text\\/plain]"),
function(node) {
idl_array.add_idls(node.textContent);
});
window.pc = new RTCPeerConnection(null);
idl_array.add_objects({"RTCPeerConnection": ["pc"]});
idl_array.test();
done();
})();
</script>
</body>
</html>

View file

@ -284,7 +284,7 @@
pc2.setRemoteDescription(offer))
.then(() =>
assert_rtcerror_rejection('idp-execution-failure',
peerIdentityPromise,
peerIdentityPromise1,
`Expect first peerIdentity promise to be rejected with RTCError('idp-execution-failure')`))
.then(() => {
const peerIdentityPromise2 = pc2.peerIdentity;

View file

@ -24,11 +24,11 @@
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
let localTrack = tracks[0];
const localTrack = tracks[0];
caller.addTrack(localTrack);
let offerPromise = performOffer(caller, callee);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
let remoteTrack = trackEvent.track;
const remoteTrack = trackEvent.track;
assert_equals(remoteTrack.id, localTrack.id,
'Expected local and remote track IDs to match.');
assert_equals(trackEvent.streams.length, 0,
@ -47,15 +47,15 @@
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
let localTrack = tracks[0];
let localStream = streams[0];
const localTrack = tracks[0];
const localStream = streams[0];
caller.addTrack(localTrack, localStream);
let offerPromise = performOffer(caller, callee);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
assert_equals(trackEvent.streams.length, 1,
'Expected track event to fire with a single stream.');
let remoteTrack = trackEvent.track;
let remoteStream = trackEvent.streams[0];
const remoteTrack = trackEvent.track;
const remoteStream = trackEvent.streams[0];
assert_equals(remoteTrack.id, localTrack.id,
'Expected local and remote track IDs to match.');
assert_equals(remoteStream.id, localStream.id,
@ -71,22 +71,50 @@
}));
}, 'addTrack() with a track and a stream makes ontrack fire with a track and a stream.');
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
let eventSequence = '';
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
const ontrackResolver = new Resolver();
callee.ontrack = () => {
eventSequence += 'ontrack;';
ontrackResolver.resolve();
}
caller.addTrack(tracks[0]);
return Promise.all([
ontrackResolver.promise,
performOffer(caller, callee).then(() => {
eventSequence += 'setRemoteDescription;';
})
]);
}))
.then(t.step_func(() => {
assert_equals(eventSequence, 'ontrack;setRemoteDescription;');
t.done();
}))
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'ontrack fires before setRemoteDescription resolves.');
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
let localTrack1 = tracks[0];
let localTrack2 = tracks[1];
let localStream = streams[0];
const localTrack1 = tracks[0];
const localTrack2 = tracks[1];
const localStream = streams[0];
caller.addTrack(localTrack1, localStream);
caller.addTrack(localTrack2, localStream);
let offerPromise = performOffer(caller, callee);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
assert_equals(trackEvent.streams.length, 1,
'Expected track event to fire with a single stream.');
let remoteTrack1 = trackEvent.track;
let remoteStream = trackEvent.streams[0];
const remoteTrack1 = trackEvent.track;
const remoteStream = trackEvent.streams[0];
assert_equals(remoteTrack1.id, localTrack1.id,
'Expected first remote track ID to match first local track ID.');
assert_equals(remoteStream.getTracks().length, 2,
@ -94,7 +122,7 @@
callee.ontrack = t.step_func(trackEvent => {
assert_equals(trackEvent.streams.length, 1,
'Expected track event to fire with a single stream.');
let remoteTrack2 = trackEvent.track;
const remoteTrack2 = trackEvent.track;
assert_equals(trackEvent.streams[0], remoteStream,
'Expected both track events to fire with the same remote stream.');
assert_equals(remoteTrack2.id, localTrack2.id,
@ -151,17 +179,53 @@
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
let eventSequence = '';
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
let localTrack = tracks[0];
let localStreams = streams;
const localTracks = tracks;
const localStream = streams[0];
caller.addTrack(localTracks[0], localStream);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
callee.ontrack = null;
const remoteStream = trackEvent.streams[0];
const onaddtrackResolver = new Resolver();
remoteStream.onaddtrack = () => {
eventSequence += 'stream.onaddtrack;';
onaddtrackResolver.resolve();
}
caller.addTrack(localTracks[1], localStream);
Promise.all([
onaddtrackResolver.promise,
performOffer(caller, callee).then(() => {
eventSequence += 'setRemoteDescription;';
})
]).then(t.step_func(() => {
assert_equals(eventSequence, 'stream.onaddtrack;setRemoteDescription;');
t.done();
}));
});
return offerPromise;
}))
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'stream.onaddtrack fires before setRemoteDescription resolves.');
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(2)
.then(t.step_func(([tracks, streams]) => {
const localTrack = tracks[0];
const localStreams = streams;
caller.addTrack(localTrack, localStreams[0], localStreams[1]);
let performOffer = performOffer(caller, callee);
const performOffer = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
assert_equals(trackEvent.streams.length, 2,
'Expected the track event to fire with two streams.');
let remoteTrack = trackEvent.track;
let remoteStreams = trackEvent.streams;
const remoteTrack = trackEvent.track;
const remoteStreams = trackEvent.streams;
assert_equals(remoteTrack.id, localTrack.id,
'Expected local and remote track IDs to match.');
assert_equals(remoteStreams[0].id, localStreams[0].id,
@ -184,38 +248,10 @@
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
let eventSequence = '';
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
caller.addTrack(tracks[0]);
let ontrackResolver = new Resolver();
callee.ontrack = () => {
eventSequence += 'ontrack;';
ontrackResolver.resolve();
}
return Promise.all([
ontrackResolver.promise,
performOffer(caller, callee).then(() => {
eventSequence += 'setRemoteDescription;';
})
]);
}))
.then(t.step_func(() => {
assert_equals(eventSequence, 'ontrack;setRemoteDescription;');
t.done();
}))
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'ontrack fires before setRemoteDescription resolves.');
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
caller.addTrack(tracks[0]);
let offerPromise = performOffer(caller, callee);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
assert_array_equals(callee.getReceivers(), [trackEvent.receiver]);
t.done();
@ -232,11 +268,11 @@
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
let sender = caller.addTrack(tracks[0]);
assert_true(sender != null);
let offerPromise = performOffer(caller, callee);
const sender = caller.addTrack(tracks[0]);
assert_not_equals(sender, null);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
let receivers = callee.getReceivers();
const receivers = callee.getReceivers();
assert_equals(receivers.length, 1,
'Expected getReceivers() to be the track event\'s receiver.');
caller.removeTrack(sender);
@ -259,9 +295,9 @@
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
let sender = caller.addTrack(tracks[0], streams[0]);
assert_true(sender != null);
let offerPromise = performOffer(caller, callee);
const sender = caller.addTrack(tracks[0], streams[0]);
assert_not_equals(sender, null);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
assert_not_equals(trackEvent.track, null);
assert_equals(trackEvent.streams.length, 1);
@ -279,21 +315,55 @@
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'removeTrack() causes onremovetrack and the track to be removed from the stream.');
}, 'removeTrack() makes stream.onremovetrack fire and the track to be removed from the stream.');
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
let eventSequence = '';
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
const sender = caller.addTrack(tracks[0], streams[0]);
assert_not_equals(sender, null);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
const remoteStream = trackEvent.streams[0];
const onremovetrackResolver = new Resolver();
remoteStream.onremovetrack = t.step_func(removeEvent => {
eventSequence += 'stream.onremovetrack;';
onremovetrackResolver.resolve();
});
caller.removeTrack(sender);
return Promise.all([
onremovetrackResolver.promise,
performOffer(caller, callee).then(() => {
eventSequence += 'setRemoteDescription;';
})
]).then(t.step_func(() => {
assert_equals(eventSequence, 'stream.onremovetrack;setRemoteDescription;');
t.done();
}));
});
return offerPromise;
}))
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'stream.onremovetrack fires before setRemoteDescription resolves.');
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
let sender = caller.addTrack(tracks[0]);
assert_true(sender != null);
let offerPromise = performOffer(caller, callee);
const sender = caller.addTrack(tracks[0]);
assert_not_equals(sender, null);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
assert_not_equals(trackEvent.track, null);
const remoteTrack = trackEvent.track;
caller.removeTrack(sender);
performOffer(caller, callee);
trackEvent.track.onmute = t.step_func(() => {
remoteTrack.onmute = t.step_func(() => {
assert_true(trackEvent.track.muted);
t.done();
});
@ -303,6 +373,54 @@
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'removeTrack() causes onmute and the track to be muted.');
}, 'removeTrack() makes track.onmute fire and the track to be muted.');
async_test(t => {
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
let eventSequence = '';
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
const sender = caller.addTrack(tracks[0]);
assert_not_equals(sender, null);
const offerPromise = performOffer(caller, callee);
callee.ontrack = t.step_func(trackEvent => {
const remoteTrack = trackEvent.track;
const onmuteResolver = new Resolver();
remoteTrack.onmute = t.step_func(() => {
eventSequence += 'track.onmute;';
onmuteResolver.resolve();
});
caller.removeTrack(sender);
return Promise.all([
onmuteResolver.promise,
performOffer(caller, callee).then(() => {
eventSequence += 'setRemoteDescription;';
})
]).then(t.step_func(() => {
assert_equals(eventSequence, 'track.onmute;setRemoteDescription;');
t.done();
}));
});
return offerPromise;
}))
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'track.onmute fires before setRemoteDescription resolves.');
async_test(t => {
const pc = new RTCPeerConnection();
return getUserMediaTracksAndStreams(1)
.then(t.step_func(([tracks, streams]) => {
const sender = pc.addTrack(tracks[0]);
assert_not_equals(sender, null);
pc.removeTrack(sender);
pc.removeTrack(sender);
t.done();
}))
.catch(t.step_func(reason => {
assert_unreached(reason);
}));
}, 'removeTrack() twice is safe.');
</script>

View file

@ -48,5 +48,5 @@ function validateCodecCapability(codec) {
}
function validateHeaderExtensionCapability(headerExt) {
assert_optional_string_field(uri);
assert_optional_string_field(headerExt, 'uri');
}

View file

@ -9,8 +9,8 @@
'use strict';
// Test is based on the following editor draft:
// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
// https://w3c.github.io/webrtc-stats/archives/20170614/webrtc-stats.html
// webrtc-pc 20171130
// webrtc-stats 20171122
// The following helper function is called from RTCStats-helper.js
// validateStatsReport
@ -18,11 +18,6 @@
/*
5.2. RTCRtpSender Interface
interface RTCRtpSender {
Promise<RTCStatsReport> getStats();
...
};
getStats
1. Let selector be the RTCRtpSender object on which the method was invoked.
2. Let p be a new promise, and run the following steps in parallel:
@ -49,6 +44,22 @@
validateStatsReport(statsReport);
assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
});
}, 'sender.getStats() should return stats report containing outbound-rtp stats');
}, 'sender.getStats() via addTransceiver should return stats report containing outbound-rtp stats');
promise_test(() => {
const pc = new RTCPeerConnection();
return navigator.mediaDevices.getUserMedia({ audio: true })
.then(mediaStream => {
const [track] = mediaStream.getTracks();
const sender = pc.addTrack(track, mediaStream);
return sender.getStats()
.then(statsReport => {
validateStatsReport(statsReport);
assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
});
})
}, 'sender.getStats() via addTrack should return stats report containing outbound-rtp stats');
</script>

View file

@ -0,0 +1,181 @@
<!doctype html>
<meta charset=utf-8>
<title>RTCSctpTransport.prototype.maxMessageSize</title>
<link rel="help" href="https://w3c.github.io/webrtc-pc/#rtcsctptransport-interface">
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="RTCPeerConnection-helper.js"></script>
<script>
'use strict';
// This test has an assert_unreached() that requires that the variable
// canSendSize (initiated below) is greater than 2, if non-zero. The reason
// is that we need two non-zero values that are less that that value for
// testing with predictable results. This is a bit unfortunate but shouldn't
// have any practical impact.
// Helper class to read SDP attributes and generate SDPs with modified attribute values
class SDPAttributeHelper {
constructor(attrName, valueRegExpStr) {
this.attrName = attrName;
this.re = new RegExp(`^a=${attrName}:(${valueRegExpStr})\\r\\n`, 'm');
}
getValue(sdp) {
const matches = sdp.match(this.re);
return matches ? matches[1] : null;
}
sdpWithValue(sdp, value) {
const matches = sdp.match(this.re);
const sdpParts = sdp.split(matches[0]);
const attributeLine = arguments.length > 1 ? `a=${this.attrName}:${value}\r\n` : '';
return `${sdpParts[0]}${attributeLine}${sdpParts[1]}`;
}
sdpWithoutAttribute(sdp) {
return this.sdpWithValue(sdp);
}
}
const mmsAttributeHelper = new SDPAttributeHelper('max-message-size', '\\d+');
let canSendSize;
const remoteValue1 = 1;
const remoteValue2 = 2;
promise_test(t => {
const pc = new RTCPeerConnection();
assert_equals(pc.sctp, null);
let maxMessageSize;
return generateOffer({ pc, data: true })
.then((offer) => {
assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
'SDP should have max-message-size attribute');
offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, 0) };
return pc.setRemoteDescription(offer);
})
.then(() => pc.createAnswer())
.then((answer) => pc.setLocalDescription(answer))
.then(() => {
assert_not_equals(pc.sctp, null);
canSendSize = pc.sctp.maxMessageSize == Number.POSITIVE_INFINITY ? 0 : pc.sctp.maxMessageSize;
if (canSendSize != 0 && canSendSize < remoteValue2) {
assert_unreached('This test needs two values that are less than canSendSize (unless it is zero)');
}
});
}, 'Determine the local side send limitation (canSendSize) by offering a max-message-size of 0');
promise_test(t => {
const pc = new RTCPeerConnection();
assert_equals(pc.sctp, null);
return generateOffer({ pc, data: true })
.then((offer) => {
assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
'SDP should have max-message-size attribute');
// Remove the max-message-size SDP attribute
offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithoutAttribute(offer.sdp) };
return pc.setRemoteDescription(offer)
})
.then(() => pc.createAnswer())
.then((answer) => pc.setLocalDescription(answer))
.then(() => {
assert_not_equals(pc.sctp, null);
// Test outcome depends on canSendSize value
if (canSendSize) {
assert_equals(pc.sctp.maxMessageSize, Math.min(65535, canSendSize),
'Missing SDP attribute and a non-zero canSendSize should give an maxMessageSize of min(65535, canSendSize)');
} else {
assert_equals(pc.sctp.maxMessageSize, 65535,
'Missing SDP attribute and a canSendSize of 0 should give an maxMessageSize of 65535');
}
});
}, 'Remote offer SDP missing max-message-size attribute');
promise_test(t => {
const pc = new RTCPeerConnection();
assert_equals(pc.sctp, null);
return generateOffer({ pc, data: true })
.then((offer) => {
assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
'SDP should have max-message-size attribute');
offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteValue1) };
return pc.setRemoteDescription(offer);
})
.then(() => pc.createAnswer())
.then((answer) => pc.setLocalDescription(answer))
.then(() => {
assert_not_equals(pc.sctp, null);
assert_equals(pc.sctp.maxMessageSize, remoteValue1,
'maxMessageSize should be the value provided by the remote peer (as long as it is less than canSendSize)');
});
}, 'max-message-size with a (non-zero) value provided by the remote peer');
promise_test(t => {
const pc = new RTCPeerConnection();
assert_equals(pc.sctp, null);
return generateOffer({ pc, data: true })
.then((offer) => {
assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
'SDP should have max-message-size attribute');
offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteValue1) };
return pc.setRemoteDescription(offer)
})
.then(() => pc.createAnswer())
.then((answer) => pc.setLocalDescription(answer))
.then(() => {
assert_not_equals(pc.sctp, null);
assert_equals(pc.sctp.maxMessageSize, remoteValue1,
'maxMessageSize should be the value provided by the remote peer (as long as it is less than canSendSize)');
})
.then(() => pc.createOffer()) // Start new O/A exchange that updates max-message-size
.then((offer) => {
offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteValue2)};
return pc.setRemoteDescription(offer)
})
.then(() => pc.createAnswer())
.then((answer) => pc.setLocalDescription(answer))
.then(() => {
assert_not_equals(pc.sctp, null);
assert_equals(pc.sctp.maxMessageSize, remoteValue2,
'maxMessageSize should be the new value provided by the remote peer (as long as it is less than canSendSize)');
})
;
}, 'Renegotiate max-message-size with a (non-zero) value provided by the remote peer');
promise_test(t => {
const pc = new RTCPeerConnection();
assert_equals(pc.sctp, null);
const largerThanCanSendSize = canSendSize + 1;
return generateOffer({ pc, data: true })
.then((offer) => {
assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
'SDP should have max-message-size attribute');
offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, largerThanCanSendSize) };
return pc.setRemoteDescription(offer)
})
.then(() => pc.createAnswer())
.then((answer) => pc.setLocalDescription(answer))
.then(() => {
assert_not_equals(pc.sctp, null);
// Test outcome depends on canSendSize value
if (canSendSize) {
assert_equals(pc.sctp.maxMessageSize, canSendSize,
'A remote value larger than a non-zero canSendSize should limit maxMessageSize to canSendSize');
} else {
assert_equals(pc.sctp.maxMessageSize, 65535,
'A canSendSize of zero should let the remote value set maxMessageSize');
}
});
}, 'max-message-size with a (non-zero) value larger than canSendSize provided by the remote peer');
</script>

View file

@ -1,18 +1,12 @@
'use strict';
// Test is based on the following editor draft:
// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
// https://w3c.github.io/webrtc-stats/archives/20170614/webrtc-stats.html
// webrtc-pc 20171130
// webrtc-stats 20171122
// This file depends on dictionary-helper.js which should
// be loaded from the main HTML file.
// To improve readability, the WebIDL definitions of the Stats
// dictionaries are modified to annotate with required fields when
// they are required by section 8.6 of webrtc-pc. ID fields are
// also annotated with the stats type that they are linked to.
/*
[webrtc-stats]
6.1. RTCStatsType enum
@ -82,6 +76,16 @@ function assert_stats_report_has_stats(statsReport, statsTypes) {
}
}
function findStatsFromReport(statsReport, predicate, message) {
for (const stats of statsReport.values()) {
if (predicate(stats)) {
return stats;
}
}
assert_unreached(message || 'none of stats in statsReport satisfy given condition')
}
// Get stats object of type that is expected to be
// found in the statsReport
function getRequiredStats(statsReport, type) {
@ -132,7 +136,7 @@ function validateOptionalIdField(statsReport, stats, field, type) {
};
*/
function validateRtcStats(statsReport, stats) {
assert_number_field(stats, 'timeStamp');
assert_number_field(stats, 'timestamp');
assert_string_field(stats, 'type');
assert_string_field(stats, 'id');
}
@ -141,35 +145,32 @@ function validateRtcStats(statsReport, stats) {
[webrtc-stats]
7.1. RTCRTPStreamStats dictionary
dictionary RTCRTPStreamStats : RTCStats {
required unsigned long ssrc;
required DOMString mediaType;
[RTCMediaStreamTrackStats]
required DOMString trackId;
[RTCTransportStats]
required DOMString transportId;
[RTCCodecStats]
required DOMString codecId;
unsigned long firCount;
unsigned long pliCount;
required unsigned long nackCount;
unsigned long sliCount;
unsigned long long qpSum;
unsigned long ssrc;
DOMString mediaType;
DOMString trackId;
DOMString transportId;
DOMString codecId;
unsigned long firCount;
unsigned long pliCount;
unsigned long nackCount;
unsigned long sliCount;
unsigned long long qpSum;
};
mediaType of type DOMString
Either "audio" or "video".
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCRTPStreamStats, with attributes ssrc, associateStatsId, isRemote, mediaType,
mediaTrackId, transportId, codecId, nackCount
- RTCRTPStreamStats, with attributes ssrc, mediaType, trackId,
transportId, codecId, nackCount
*/
function validateRtpStreamStats(statsReport, stats) {
validateRtcStats(statsReport, stats);
assert_unsigned_int_field(stats, 'ssrc');
assert_string_field(stats, 'mediaType');
assert_enum_field(stats, 'mediaType', ['audio', 'video'])
validateIdField(statsReport, stats, 'trackId', 'track');
validateIdField(statsReport, stats, 'transportId', 'transport');
@ -186,15 +187,12 @@ function validateRtpStreamStats(statsReport, stats) {
[webrtc-stats]
7.2. RTCCodecStats dictionary
dictionary RTCCodecStats : RTCStats {
required unsigned long payloadType;
required RTCCodecType codecType;
[RTCTransportStats]
unsigned long payloadType;
RTCCodecType codecType;
DOMString transportId;
DOMString mimeType;
required unsigned long clockRate;
required unsigned long channels;
unsigned long clockRate;
unsigned long channels;
DOMString sdpFmtpLine;
DOMString implementation;
};
@ -206,7 +204,7 @@ function validateRtpStreamStats(statsReport, stats) {
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCCodecStats, with attributes payloadType, codec, clockRate, channels, parameters
- RTCCodecStats, with attributes payloadType, codec, clockRate, channels, sdpFmtpLine
*/
function validateCodecStats(statsReport, stats) {
@ -221,7 +219,7 @@ function validateCodecStats(statsReport, stats) {
assert_unsigned_int_field(stats, 'clockRate');
assert_unsigned_int_field(stats, 'channels');
assert_optional_string_field(stats, 'sdpFmtpLine');
assert_string_field(stats, 'sdpFmtpLine');
assert_optional_string_field(stats, 'implementation');
}
@ -229,34 +227,42 @@ function validateCodecStats(statsReport, stats) {
[webrtc-stats]
7.3. RTCReceivedRTPStreamStats dictionary
dictionary RTCReceivedRTPStreamStats : RTCRTPStreamStats {
unsigned long packetsReceived;
unsigned long long bytesReceived;
unsigned long packetsLost;
double jitter;
double fractionLost;
unsigned long packetsDiscarded;
unsigned long packetsRepaired;
unsigned long burstPacketsLost;
unsigned long burstPacketsDiscarded;
unsigned long burstLossCount;
unsigned long burstDiscardCount;
double burstLossRate;
double burstDiscardRate;
double gapLossRate;
double gapDiscardRate;
unsigned long packetsReceived;
unsigned long long bytesReceived;
long packetsLost;
double jitter;
double fractionLost;
unsigned long packetsDiscarded;
unsigned long packetsFailedDecryption;
unsigned long packetsRepaired;
unsigned long burstPacketsLost;
unsigned long burstPacketsDiscarded;
unsigned long burstLossCount;
unsigned long burstDiscardCount;
double burstLossRate;
double burstDiscardRate;
double gapLossRate;
double gapDiscardRate;
};
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCReceivedRTPStreamStats, with all required attributes from its
inherited dictionaries, and also attributes packetsReceived,
bytesReceived, packetsLost, jitter, packetsDiscarded
*/
function validateReceivedRtpStreamStats(statsReport, stats) {
validateRtpStreamStats(statsReport, stats);
assert_optional_unsigned_int_field(stats, 'packetsReceived');
assert_optional_unsigned_int_field(stats, 'bytesReceived');
assert_optional_unsigned_int_field(stats, 'packetsLost');
assert_unsigned_int_field(stats, 'packetsReceived');
assert_unsigned_int_field(stats, 'bytesReceived');
assert_unsigned_int_field(stats, 'packetsLost');
assert_optional_number_field(stats, 'jitter');
assert_number_field(stats, 'jitter');
assert_optional_number_field(stats, 'fractionLost');
assert_optional_unsigned_int_field(stats, 'packetsDiscarded');
assert_unsigned_int_field(stats, 'packetsDiscarded');
assert_optional_unsigned_int_field(stats, 'packetsFailedDecryption');
assert_optional_unsigned_int_field(stats, 'packetsRepaired');
assert_optional_unsigned_int_field(stats, 'burstPacketsLost');
assert_optional_unsigned_int_field(stats, 'burstPacketsDiscarded');
@ -273,37 +279,21 @@ function validateReceivedRtpStreamStats(statsReport, stats) {
[webrtc-stats]
7.4. RTCInboundRTPStreamStats dictionary
dictionary RTCInboundRTPStreamStats : RTCReceivedRTPStreamStats {
required unsigned long packetsReceived;
required unsigned long long bytesReceived;
required unsigned long packetsLost;
required double jitter;
required unsigned long packetsDiscarded;
[RTCRemoteOutboundRTPStreamStats]
DOMString remoteId;
unsigned long framesDecoded;
DOMHighResTimeStamp lastPacketReceivedTimestamp;
};
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCInboundRTPStreamStats, with all required attributes from RTCRTPStreamStats,
and also attributes packetsReceived, bytesReceived, packetsLost, jitter,
packetsDiscarded
- RTCInboundRTPStreamStats, with all required attributes from its inherited
dictionaries, and also attributes remoteId, framesDecoded
*/
function validateInboundRtpStreamStats(statsReport, stats) {
validateReceivedRtpStreamStats(statsReport, stats);
assert_unsigned_int_field(stats, 'packetsReceived');
assert_unsigned_int_field(stats, 'bytesReceived');
assert_unsigned_int_field(stats, 'packetsLost');
assert_number_field(stats, 'jitter');
assert_unsigned_int_field(stats, 'packetsDiscarded');
validateOptionalIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp');
assert_optional_unsigned_int_field(stats, 'framesDecoded');
validateIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp');
assert_unsigned_int_field(stats, 'framesDecoded');
assert_optional_number_field(stats, 'lastPacketReceivedTimeStamp');
}
@ -311,18 +301,20 @@ function validateInboundRtpStreamStats(statsReport, stats) {
[webrtc-stats]
7.5. RTCRemoteInboundRTPStreamStats dictionary
dictionary RTCRemoteInboundRTPStreamStats : RTCReceivedRTPStreamStats {
[RTCOutboundRTPStreamStats]
DOMString localId;
double roundTripTime;
DOMString localId;
double roundTripTime;
};
*/
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCRemoteInboundRTPStreamStats, with all required attributes from its
inherited dictionaries, and also attributes localId, roundTripTime
*/
function validateRemoteInboundRtpStreamStats(statsReport, stats) {
validateReceivedRtpStreamStats(statsReport, stats);
validateOptionalIdField(statsReport, stats, 'localId', 'outbound-rtp');
assert_optional_number_field(stats, 'roundTripTime');
validateIdField(statsReport, stats, 'localId', 'outbound-rtp');
assert_number_field(stats, 'roundTripTime');
}
/*
@ -334,13 +326,18 @@ function validateRemoteInboundRtpStreamStats(statsReport, stats) {
unsigned long long bytesSent;
unsigned long long bytesDiscardedOnSend;
};
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCSentRTPStreamStats, with all required attributes from its inherited
dictionaries, and also attributes packetsSent, bytesSent
*/
function validateSentRtpStreamStats(statsReport, stats) {
validateRtpStreamStats(statsReport, stats);
assert_optional_unsigned_int_field(stats, 'packetsSent');
assert_unsigned_int_field(stats, 'packetsSent');
assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
assert_optional_unsigned_int_field(stats, 'bytesSent');
assert_unsigned_int_field(stats, 'bytesSent');
assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
}
@ -348,12 +345,7 @@ function validateSentRtpStreamStats(statsReport, stats) {
[webrtc-stats]
7.7. RTCOutboundRTPStreamStats dictionary
dictionary RTCOutboundRTPStreamStats : RTCSentRTPStreamStats {
required unsigned long packetsSent;
required unsigned long long bytesSent;
[RTCRemoteInboundRTPStreamStats]
DOMString remoteId;
DOMHighResTimeStamp lastPacketSentTimestamp;
double targetBitrate;
unsigned long framesEncoded;
@ -361,20 +353,19 @@ function validateSentRtpStreamStats(statsReport, stats) {
double averageRTCPInterval;
};
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCOutboundRTPStreamStats, with all required attributes from RTCRTPStreamStats,
and also attributes packetsSent, bytesSent, roundTripTime
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCOutboundRTPStreamStats, with all required attributes from its
inherited dictionaries, and also attributes remoteId, framesEncoded
*/
function validateOutboundRtpStreamStats(statsReport, stats) {
validateOptionalIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp');
validateSentRtpStreamStats(statsReport, stats)
assert_unsigned_int_field(stats, 'packetsSent');
assert_unsigned_int_field(stats, 'bytesSent');
validateIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp');
assert_optional_number_field(stats, 'lastPacketSentTimestamp');
assert_optional_number_field(stats, 'targetBitrate');
assert_optional_unsigned_int_field(stats, 'framesEncoded');
assert_unsigned_int_field(stats, 'framesEncoded');
assert_optional_number_field(stats, 'totalEncodeTime');
assert_optional_number_field(stats, 'averageRTCPInterval');
}
@ -383,17 +374,20 @@ function validateOutboundRtpStreamStats(statsReport, stats) {
[webrtc-stats]
7.8. RTCRemoteOutboundRTPStreamStats dictionary
dictionary RTCRemoteOutboundRTPStreamStats : RTCSentRTPStreamStats {
[RTCInboundRTPStreamStats]
DOMString localId;
DOMHighResTimeStamp remoteTimestamp;
};
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCRemoteOutboundRTPStreamStats, with all required attributes from its
inherited dictionaries, and also attributes localId, remoteTimestamp
*/
function validateRemoteOutboundRtpStreamStats(statsReport, stats) {
validateSentRtpStreamStats(statsReport, stats);
validateOptionalIdField(statsReport, stats, 'localId', 'inbound-rtp');
assert_optional_number_field(stats, 'remoteTimeStamp');
validateIdField(statsReport, stats, 'localId', 'inbound-rtp');
assert_number_field(stats, 'remoteTimeStamp');
}
/*
@ -401,10 +395,7 @@ function validateRemoteOutboundRtpStreamStats(statsReport, stats) {
7.9. RTCRTPContributingSourceStats
dictionary RTCRTPContributingSourceStats : RTCStats {
unsigned long contributorSsrc;
[RTCInboundRTPStreamStats]
DOMString inboundRtpStreamId;
unsigned long packetsContributedTo;
double audioLevel;
};
@ -423,10 +414,10 @@ function validateContributingSourceStats(statsReport, stats) {
[webrtc-stats]
7.10. RTCPeerConnectionStats dictionary
dictionary RTCPeerConnectionStats : RTCStats {
required unsigned long dataChannelsOpened;
required unsigned long dataChannelsClosed;
unsigned long dataChannelsRequested;
unsigned long dataChannelsAccepted;
unsigned long dataChannelsOpened;
unsigned long dataChannelsClosed;
unsigned long dataChannelsRequested;
unsigned long dataChannelsAccepted;
};
[webrtc-pc]
@ -446,10 +437,8 @@ function validatePeerConnectionStats(statsReport, stats) {
[webrtc-stats]
7.11. RTCMediaStreamStats dictionary
dictionary RTCMediaStreamStats : RTCStats {
required DOMString streamIdentifier;
[RTCMediaStreamTrackStats]
required sequence<DOMString> trackIds;
DOMString streamIdentifier;
sequence<DOMString> trackIds;
};
[webrtc-pc]
@ -479,35 +468,37 @@ function validateMediaStreamStats(statsReport, stats) {
[webrtc-stats]
7.12. RTCMediaStreamTrackStats dictionary
dictionary RTCMediaStreamTrackStats : RTCStats {
required DOMString trackIdentifier;
required boolean remoteSource;
required boolean ended;
required boolean detached;
DOMString kind;
DOMHighResTimeStamp estimatedPlayoutTimestamp;
required unsigned long frameWidth;
required unsigned long frameHeight;
required double framesPerSecond;
unsigned long framesCaptured;
required unsigned long framesSent;
required unsigned long framesReceived;
required unsigned long framesDecoded;
required unsigned long framesDropped;
required unsigned long framesCorrupted;
unsigned long partialFramesLost;
unsigned long fullFramesLost;
required double audioLevel;
double totalAudioEnergy;
boolean voiceActivityFlag;
double echoReturnLoss;
double echoReturnLossEnhancement;
unsigned long long totalSamplesSent;
unsigned long long totalSamplesReceived;
double totalSamplesDuration;
unsigned long long concealedSamples;
unsigned long long concealmentEvents;
double jitterBufferDelay;
RTCPriorityType priority;
DOMString trackIdentifier;
boolean remoteSource;
boolean ended;
boolean detached;
DOMString kind;
DOMHighResTimeStamp estimatedPlayoutTimestamp;
unsigned long frameWidth;
unsigned long frameHeight;
double framesPerSecond;
unsigned long framesCaptured;
unsigned long framesSent;
unsigned long keyFramesSent;
unsigned long framesReceived;
unsigned long keyFramesReceived;
unsigned long framesDecoded;
unsigned long framesDropped;
unsigned long framesCorrupted;
unsigned long partialFramesLost;
unsigned long fullFramesLost;
double audioLevel;
double totalAudioEnergy;
boolean voiceActivityFlag;
double echoReturnLoss;
double echoReturnLossEnhancement;
unsigned long long totalSamplesSent;
unsigned long long totalSamplesReceived;
double totalSamplesDuration;
unsigned long long concealedSamples;
unsigned long long concealmentEvents;
double jitterBufferDelay;
RTCPriorityType priority;
};
[webrtc-pc]
@ -520,48 +511,50 @@ function validateMediaStreamStats(statsReport, stats) {
};
8.6. Mandatory To Implement Stats
- RTCMediaStreamTrackStats, with attributes trackIdentifier, remoteSource, ended,
detached, ssrcIds, frameWidth, frameHeight, framesPerSecond, framesSent,
- RTCMediaStreamTrackStats, with attributes trackIdentifier, remoteSource,
ended, detached, frameWidth, frameHeight, framesPerSecond, framesSent,
framesReceived, framesDecoded, framesDropped, framesCorrupted, audioLevel
*/
function validateMediaStreamTrackStats(stats, stat) {
function validateMediaStreamTrackStats(statsReport, stats) {
validateRtcStats(statsReport, stats);
assert_string_field(stat, 'trackIdentifier');
assert_boolean_field(stat, 'remoteSource');
assert_boolean_field(stat, 'ended');
assert_boolean_field(stat, 'detached');
assert_string_field(stats, 'trackIdentifier');
assert_boolean_field(stats, 'remoteSource');
assert_boolean_field(stats, 'ended');
assert_boolean_field(stats, 'detached');
assert_optional_string_field(stat, 'kind');
assert_optional_number_field(stat, 'estimatedPlayoutTimestamp');
assert_optional_enum_field(stats, 'kind', ['audio', 'video']);
assert_optional_number_field(stats, 'estimatedPlayoutTimestamp');
assert_unsigned_int_field(stat, 'frameWidth');
assert_unsigned_int_field(stat, 'frameHeight');
assert_number_field(stat, 'framesPerSecond');
assert_unsigned_int_field(stats, 'frameWidth');
assert_unsigned_int_field(stats, 'frameHeight');
assert_number_field(stats, 'framesPerSecond');
assert_optional_unsigned_int_field(stat, 'framesCaptured');
assert_unsigned_int_field(stat, 'frameSent');
assert_unsigned_int_field(stat, 'frameReceived');
assert_unsigned_int_field(stat, 'frameDecoded');
assert_unsigned_int_field(stat, 'frameDropped');
assert_unsigned_int_field(stat, 'frameCorrupted');
assert_optional_unsigned_int_field(stats, 'framesCaptured');
assert_unsigned_int_field(stats, 'framesSent');
assert_optional_unsigned_int_field(stats, 'keyFramesSent');
assert_unsigned_int_field(stats, 'framesReceived');
assert_optional_unsigned_int_field(stats, 'keyFramesReceived');
assert_unsigned_int_field(stats, 'framesDecoded');
assert_unsigned_int_field(stats, 'framesDropped');
assert_unsigned_int_field(stats, 'framesCorrupted');
assert_optional_unsigned_int_field(stat, 'partialFramesLost');
assert_optional_unsigned_int_field(stat, 'fullFramesLost');
assert_optional_unsigned_int_field(stats, 'partialFramesLost');
assert_optional_unsigned_int_field(stats, 'fullFramesLost');
assert_number_field(stat, 'audioLevel');
assert_optional_number_field(stat, 'totalAudioEnergy');
assert_optional_boolean_field(stat, 'voiceActivityFlag');
assert_optional_number_field(stat, 'echoReturnLoss');
assert_optional_number_field(stat, 'echoReturnLossEnhancement');
assert_number_field(stats, 'audioLevel');
assert_optional_number_field(stats, 'totalAudioEnergy');
assert_optional_boolean_field(stats, 'voiceActivityFlag');
assert_optional_number_field(stats, 'echoReturnLoss');
assert_optional_number_field(stats, 'echoReturnLossEnhancement');
assert_optional_unsigned_int_field(stat, 'totalSamplesSent');
assert_optional_unsigned_int_field(stat, 'totalSamplesReceived');
assert_optional_number_field(stat, 'totalSamplesDuration');
assert_optional_unsigned_int_field(stat, 'concealedSamples');
assert_optional_unsigned_int_field(stat, 'concealmentEvents');
assert_optional_number_field(stat, 'jitterBufferDelay');
assert_optional_unsigned_int_field(stats, 'totalSamplesSent');
assert_optional_unsigned_int_field(stats, 'totalSamplesReceived');
assert_optional_number_field(stats, 'totalSamplesDuration');
assert_optional_unsigned_int_field(stats, 'concealedSamples');
assert_optional_unsigned_int_field(stats, 'concealmentEvents');
assert_optional_number_field(stats, 'jitterBufferDelay');
assert_optional_enum_field(stats, 'priority',
['very-low', 'low', 'medium', 'high']);
@ -571,18 +564,15 @@ function validateMediaStreamTrackStats(stats, stat) {
[webrtc-stats]
7.13. RTCDataChannelStats dictionary
dictionary RTCDataChannelStats : RTCStats {
required DOMString label;
required DOMString protocol;
required long datachannelid;
[RTCTransportStats]
DOMString transportId;
required RTCDataChannelState state;
required unsigned long messagesSent;
required unsigned long long bytesSent;
required unsigned long messagesReceived;
required unsigned long long bytesReceived;
DOMString label;
DOMString protocol;
long dataChannelIdentifier;
DOMString transportId;
RTCDataChannelState state;
unsigned long messagesSent;
unsigned long long bytesSent;
unsigned long messagesReceived;
unsigned long long bytesReceived;
};
[webrtc-pc]
@ -598,22 +588,19 @@ function validateMediaStreamTrackStats(stats, stat) {
- RTCDataChannelStats, with attributes label, protocol, datachannelId, state,
messagesSent, bytesSent, messagesReceived, bytesReceived
*/
function validateDataChannelStats(statsReport, stats) {
validateRtcStats(statsReport, stats);
assert_string_field(stats, 'label');
assert_string_field(stats, 'protocol');
assert_int_field(stats, 'datachannelid');
assert_int_field(stats, 'dataChannelIdentifier');
validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
assert_enum_field(stats, 'state',
['connecting', 'open', 'closing', 'closed']);
assert_unsigned_int_field(stats, 'messageSent');
assert_unsigned_int_field(stats, 'messageSent');
assert_unsigned_int_field(stats, 'messagesSent');
assert_unsigned_int_field(stats, 'bytesSent');
assert_unsigned_int_field(stats, 'messagesReceived');
assert_unsigned_int_field(stats, 'bytesReceived');
@ -623,25 +610,16 @@ function validateDataChannelStats(statsReport, stats) {
[webrtc-stats]
7.14. RTCTransportStats dictionary
dictionary RTCTransportStats : RTCStats {
unsigned long packetsSent;
unsigned long packetsReceived;
required unsigned long long bytesSent;
required unsigned long long bytesReceived;
[RTCTransportStats]
required DOMString rtcpTransportStatsId;
RTCIceRole iceRole;
RTCDtlsTransportState dtlsState;
[RTCIceCandidatePairStats]
required DOMString selectedCandidatePairId;
[RTCCertificateStats]
required DOMString localCertificateId;
[RTCCertificateStats]
required DOMString remoteCertificateId;
unsigned long packetsSent;
unsigned long packetsReceived;
unsigned long long bytesSent;
unsigned long long bytesReceived;
DOMString rtcpTransportStatsId;
RTCIceRole iceRole;
RTCDtlsTransportState dtlsState;
DOMString selectedCandidatePairId;
DOMString localCertificateId;
DOMString remoteCertificateId;
};
[webrtc-pc]
@ -661,10 +639,10 @@ function validateDataChannelStats(statsReport, stats) {
};
8.6. Mandatory To Implement Stats
- RTCTransportStats, with attributes bytesSent, bytesReceived, rtcpTransportStatsId,
activeConnection, selectedCandidatePairId, localCertificateId, remoteCertificateId
- RTCTransportStats, with attributes bytesSent, bytesReceived,
rtcpTransportStatsId, selectedCandidatePairId, localCertificateId,
remoteCertificateId
*/
function validateTransportStats(statsReport, stats) {
validateRtcStats(statsReport, stats);
@ -682,26 +660,35 @@ function validateTransportStats(statsReport, stats) {
['new', 'connecting', 'connected', 'closed', 'failed']);
validateIdField(statsReport, stats, 'selectedCandidatePairId', 'candidate-pair');
validateIdField(stateReport, stats, 'localCertificateId', 'certificate');
validateIdField(stateReport, stats, 'remoteCertificateId', 'certificate');
validateIdField(statsReport, stats, 'localCertificateId', 'certificate');
validateIdField(statsReport, stats, 'remoteCertificateId', 'certificate');
}
/*
[webrtc-stats]
7.15. RTCIceCandidateStats dictionary
dictionary RTCIceCandidateStats : RTCStats {
[RTCTransportStats]
DOMString transportId;
DOMString transportId;
boolean isRemote;
RTCNetworkType networkType;
DOMString ip;
long port;
DOMString protocol;
RTCIceCandidateType candidateType;
long priority;
DOMString url;
DOMString relayProtocol;
boolean deleted = false;
};
boolean isRemote;
required DOMString ip;
required long port;
required DOMString protocol;
required RTCIceCandidateType candidateType;
required long priority;
required DOMString url;
DOMString relayProtocol;
boolean deleted = false;
enum RTCNetworkType {
"bluetooth",
"cellular",
"ethernet",
"wifi",
"wimax",
"vpn",
"unknown"
};
[webrtc-pc]
@ -714,16 +701,18 @@ function validateTransportStats(statsReport, stats) {
};
8.6. Mandatory To Implement Stats
- RTCIceCandidateStats, with attributes ip, port, protocol, candidateType, priority,
url
- RTCIceCandidateStats, with attributes ip, port, protocol, candidateType,
priority, url
*/
function validateIceCandidateStats(statsReport, stats) {
validateRtcStats(statsReport, stats);
validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
assert_optional_boolean_field(stats, 'isRemote');
assert_optional_enum_field(stats, 'networkType',
['bluetooth', 'cellular', 'ethernet', 'wifi', 'wimax', 'vpn', 'unknown'])
assert_string_field(stats, 'ip');
assert_int_field(stats, 'port');
assert_string_field(stats, 'protocol');
@ -741,40 +730,34 @@ function validateIceCandidateStats(statsReport, stats) {
[webrtc-stats]
7.16. RTCIceCandidatePairStats dictionary
dictionary RTCIceCandidatePairStats : RTCStats {
[RTCTransportStats]
required DOMString transportId;
[RTCIceCandidateStats]
required DOMString localCandidateId;
[RTCIceCandidateStats]
required DOMString remoteCandidateId;
required RTCStatsIceCandidatePairState state;
required unsigned long long priority;
required boolean nominated;
unsigned long packetsSent;
unsigned long packetsReceived;
required unsigned long long bytesSent;
required unsigned long long bytesReceived;
DOMHighResTimeStamp lastPacketSentTimestamp;
DOMHighResTimeStamp lastPacketReceivedTimestamp;
DOMHighResTimeStamp firstRequestTimestamp;
DOMHighResTimeStamp lastRequestTimestamp;
DOMHighResTimeStamp lastResponseTimestamp;
required double totalRoundTripTime;
required double currentRoundTripTime;
double availableOutgoingBitrate;
double availableIncomingBitrate;
unsigned long circuitBreakerTriggerCount;
unsigned long long requestsReceived;
unsigned long long requestsSent;
unsigned long long responsesReceived;
unsigned long long responsesSent;
unsigned long long retransmissionsReceived;
unsigned long long retransmissionsSent;
unsigned long long consentRequestsSent;
DOMHighResTimeStamp consentExpiredTimestamp;
DOMString transportId;
DOMString localCandidateId;
DOMString remoteCandidateId;
RTCStatsIceCandidatePairState state;
unsigned long long priority;
boolean nominated;
unsigned long packetsSent;
unsigned long packetsReceived;
unsigned long long bytesSent;
unsigned long long bytesReceived;
DOMHighResTimeStamp lastPacketSentTimestamp;
DOMHighResTimeStamp lastPacketReceivedTimestamp;
DOMHighResTimeStamp firstRequestTimestamp;
DOMHighResTimeStamp lastRequestTimestamp;
DOMHighResTimeStamp lastResponseTimestamp;
double totalRoundTripTime;
double currentRoundTripTime;
double availableOutgoingBitrate;
double availableIncomingBitrate;
unsigned long circuitBreakerTriggerCount;
unsigned long long requestsReceived;
unsigned long long requestsSent;
unsigned long long responsesReceived;
unsigned long long responsesSent;
unsigned long long retransmissionsReceived;
unsigned long long retransmissionsSent;
unsigned long long consentRequestsSent;
DOMHighResTimeStamp consentExpiredTimestamp;
};
enum RTCStatsIceCandidatePairState {
@ -788,8 +771,7 @@ function validateIceCandidateStats(statsReport, stats) {
[webrtc-pc]
8.6. Mandatory To Implement Stats
- RTCIceCandidatePairStats, with attributes transportId, localCandidateId,
remoteCandidateId, state, priority, nominated, writable, readable, bytesSent,
bytesReceived, totalRtt, currentRtt
remoteCandidateId, state, priority, nominated, bytesSent, bytesReceived, totalRoundTripTime, currentRoundTripTime
*/
function validateIceCandidatePairStats(statsReport, stats) {
validateRtcStats(statsReport, stats);
@ -835,10 +817,10 @@ function validateIceCandidatePairStats(statsReport, stats) {
[webrtc-stats]
7.17. RTCCertificateStats dictionary
dictionary RTCCertificateStats : RTCStats {
required DOMString fingerprint;
required DOMString fingerprintAlgorithm;
required DOMString base64Certificate;
required DOMString issuerCertificateId;
DOMString fingerprint;
DOMString fingerprintAlgorithm;
DOMString base64Certificate;
DOMString issuerCertificateId;
};
[webrtc-pc]
@ -846,7 +828,6 @@ function validateIceCandidatePairStats(statsReport, stats) {
- RTCCertificateStats, with attributes fingerprint, fingerprintAlgorithm,
base64Certificate, issuerCertificateId
*/
function validateCertificateStats(statsReport, stats) {
validateRtcStats(statsReport, stats);

View file

@ -41,6 +41,7 @@
assert_equals(trackEvent.receiver, receiver);
assert_equals(trackEvent.track, track);
assert_array_equals(trackEvent.streams, []);
assert_equals(trackEvent.streams, trackEvent.streams); // [SameObject]
assert_equals(trackEvent.transceiver, transceiver);
assert_equals(trackEvent.type, 'track');

View file

@ -1,75 +0,0 @@
<!doctype html>
<!--
This test creates a data channel object and compares it with the WebIDL defined interface
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>RTCPeerConnection Data Channel Empty String Test</title>
<link rel="author" title="Dominique Hazael-Massieux" href="mailto:dom@w3.org"/>
<link rel="help" href="http://w3c.github.io/webrtc-pc/#rtcdatachannel">
</head>
<body>
<div id="log"></div>
<!-- These files are in place when executing on W3C. -->
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
<!-- The IDL is copied from https://w3c.github.io/webrtc-pc/archives/20161219/webrtc.html -->
<script type="text/plain">
interface RTCDataChannel : EventTarget {
readonly attribute USVString label;
readonly attribute boolean ordered;
readonly attribute unsigned short? maxPacketLifeTime;
readonly attribute unsigned short? maxRetransmits;
readonly attribute USVString protocol;
readonly attribute boolean negotiated;
readonly attribute unsigned short id;
readonly attribute RTCPriorityType priority;
readonly attribute RTCDataChannelState readyState;
readonly attribute unsigned long bufferedAmount;
attribute unsigned long bufferedAmountLowThreshold;
attribute EventHandler onopen;
attribute EventHandler onbufferedamountlow;
attribute EventHandler onerror;
attribute EventHandler onclose;
void close();
attribute EventHandler onmessage;
attribute DOMString binaryType;
void send(USVString data);
void send(Blob data);
void send(ArrayBuffer data);
void send(ArrayBufferView data);
};
enum RTCPriorityType {
"very-low",
"low",
"medium",
"high"
};
enum RTCDataChannelState {
"connecting",
"open",
"closing",
"closed"
};
</script>
<script type="text/javascript">
(function() {
var idl_array = new IdlArray();
[].forEach.call(document.querySelectorAll("script[type=text\\/plain]"),
function(node) {
idl_array.add_idls(node.textContent);
});
pc = new RTCPeerConnection(null);
window.channel = pc.createDataChannel("test");
idl_array.add_objects({"RTCDataChannel": ["channel"]});
idl_array.test();
done();
})();
</script>
</body>
</html>

View file

@ -0,0 +1,156 @@
module.exports = {
rules: {
'no-undef': 1,
'no-unused-vars': 0
},
plugins: [
'html'
],
env: {
browser: true,
es6: true
},
globals: {
// testharness globals
test: true,
async_test: true,
promise_test: true,
promise_rejects: true,
IdlArray: true,
assert_true: true,
assert_false: true,
assert_equals: true,
assert_not_equals: true,
assert_array_equals: true,
assert_in_array: true,
assert_unreached: true,
assert_throws: true,
assert_idl_attribute: true,
assert_exists: true,
assert_greater_than: true,
assert_less_than: true,
assert_greater_than_equal: true,
assert_less_than_equal: true,
assert_approx_equals: true,
// WebRTC globals
RTCPeerConnection: true,
RTCRtpSender: true,
RTCRtpReceiver: true,
RTCRtpTransceiver: true,
RTCIceTransport: true,
RTCDtlsTransport: true,
RTCSctpTransport: true,
RTCDataChannel: true,
RTCCertificate: true,
RTCDTMFSender: true,
RTCError: true,
RTCTrackEvent: true,
RTCPeerConnectionIceEvent: true,
RTCDTMFToneChangeEvent: true,
RTCDataChannelEvent: true,
RTCRtpContributingSource: true,
RTCRtpSynchronizationSource: true,
// dictionary-helper.js
assert_unsigned_int_field: true,
assert_int_field: true,
assert_string_field: true,
assert_number_field: true,
assert_boolean_field: true,
assert_array_field: true,
assert_dict_field: true,
assert_enum_field: true,
assert_optional_unsigned_int_field: true,
assert_optional_int_field: true,
assert_optional_string_field: true,
assert_optional_number_field: true,
assert_optional_boolean_field: true,
assert_optional_array_field: true,
assert_optional_dict_field: true,
assert_optional_enum_field: true,
// identity-helper.js
parseAssertionResult: true,
getIdpDomains: true,
assert_rtcerror_rejection: true,
hostString: true,
// RTCConfiguration-helper.js
config_test: true,
// RTCDTMFSender-helper.js
createDtmfSender: true,
test_tone_change_events: true,
getTransceiver: true,
// RTCPeerConnection-helper.js
countLine: true,
countAudioLine: true,
countVideoLine: true,
countApplicationLine: true,
similarMediaDescriptions: true,
assert_is_session_description: true,
isSimilarSessionDescription: true,
assert_session_desc_equals: true,
assert_session_desc_not_equals: true,
generateOffer: true,
generateAnswer: true,
test_state_change_event: true,
test_never_resolve: true,
exchangeIceCandidates: true,
doSignalingHandshake: true,
createDataChannelPair: true,
awaitMessage: true,
blobToArrayBuffer: true,
assert_equals_array_buffer: true,
generateMediaStreamTrack: true,
getTrackFromUserMedia: true,
getUserMediaTracksAndStreams: true,
performOffer: true,
Resolver: true,
// RTCRtpCapabilities-helper.js
validateRtpCapabilities: true,
validateCodecCapability: true,
validateHeaderExtensionCapability: true,
// RTCRtpParameters-helper.js
validateSenderRtpParameters: true,
validateReceiverRtpParameters: true,
validateRtpParameters: true,
validateEncodingParameters: true,
validateRtcpParameters: true,
validateHeaderExtensionParameters: true,
validateCodecParameters: true,
// RTCStats-helper.js
validateStatsReport: true,
assert_stats_report_has_stats: true,
findStatsFromReport: true,
getRequiredStats: true,
getStatsById: true,
validateIdField: true,
validateOptionalIdField: true,
validateRtcStats: true,
validateRtpStreamStats: true,
validateCodecStats: true,
validateReceivedRtpStreamStats: true,
validateInboundRtpStreamStats: true,
validateRemoteInboundRtpStreamStats: true,
validateSentRtpStreamStats: true,
validateOutboundRtpStreamStats: true,
validateRemoteOutboundRtpStreamStats: true,
validateContributingSourceStats: true,
validatePeerConnectionStats: true,
validateMediaStreamStats: true,
validateMediaStreamTrackStats: true,
validateDataChannelStats: true,
validateTransportStats: true,
validateIceCandidateStats: true,
validateIceCandidatePairStats: true,
validateCertificateStats: true,
}
}

View file

@ -0,0 +1,14 @@
WebRTC Tools
============
This directory contains a simple Node.js project to aid the development of
WebRTC tests.
## Lint
```bash
npm run lint
```
Does basic linting of the JavaScript code. Mainly for catching usage of
undefined variables.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
{
"name": "webrtc-testing-tools",
"version": "1.0.0",
"description": "Tools for WebRTC testing",
"scripts": {
"lint": "eslint -c .eslintrc.js ../*.html ../*.js"
},
"devDependencies": {
"eslint": "^4.11.0",
"eslint-plugin-html": "^4.0.0"
},
"license": "BSD",
"private": true
}