295 lines
11 KiB
HTML
295 lines
11 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Testing basic video exchange from offerer to receiver</title>
|
|
<script src="../resources/testharness.js"></script>
|
|
<script src="../resources/testharnessreport.js"></script>
|
|
</head>
|
|
<body>
|
|
<script src ="routines.js"></script>
|
|
<script>
|
|
function getStatsType(connection)
|
|
{
|
|
return connection.getStats().then((report) => {
|
|
var reportTypes = [];
|
|
report.forEach((statItem) => {
|
|
if (reportTypes.indexOf(statItem.type) === -1)
|
|
reportTypes.push(statItem.type);
|
|
});
|
|
return reportTypes.sort();
|
|
});
|
|
}
|
|
|
|
function checkStatsReportIterator(report)
|
|
{
|
|
assert_equals(Object.getOwnPropertyDescriptor(report.__proto__, Symbol.iterator).value, Object.getOwnPropertyDescriptor(report.__proto__, 'entries').value);
|
|
assert_equals(Object.getOwnPropertyDescriptor(report.__proto__, Symbol.iterator).value.name, "entries");
|
|
for (let pair of report)
|
|
assert_equals(pair.length, 2);
|
|
}
|
|
|
|
function getAudioSourceStats(connection)
|
|
{
|
|
return connection.getStats().then((report) => {
|
|
checkStatsReportIterator(report);
|
|
var stats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === "media-source" && statItem.kind === "audio") {
|
|
stats = statItem;
|
|
}
|
|
});
|
|
return stats;
|
|
});
|
|
}
|
|
|
|
function getVideoSourceStats(connection)
|
|
{
|
|
return connection.getStats().then((report) => {
|
|
checkStatsReportIterator(report);
|
|
var stats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === "media-source" && statItem.kind === "video") {
|
|
stats = statItem;
|
|
}
|
|
});
|
|
return stats;
|
|
});
|
|
}
|
|
|
|
function getInboundRTPStats(connection)
|
|
{
|
|
return connection.getStats().then((report) => {
|
|
checkStatsReportIterator(report);
|
|
var stats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === "inbound-rtp") {
|
|
stats = statItem;
|
|
}
|
|
});
|
|
return stats;
|
|
});
|
|
}
|
|
|
|
function getRemoteInboundRTPStats(connection)
|
|
{
|
|
return connection.getStats().then((report) => {
|
|
checkStatsReportIterator(report);
|
|
var stats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === "remote-inbound-rtp") {
|
|
stats = statItem;
|
|
}
|
|
});
|
|
return stats;
|
|
});
|
|
}
|
|
|
|
function getOutboundRTPStats(connection)
|
|
{
|
|
return connection.getStats().then((report) => {
|
|
checkStatsReportIterator(report);
|
|
var stats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === "outbound-rtp") {
|
|
stats = statItem;
|
|
}
|
|
});
|
|
return stats;
|
|
});
|
|
}
|
|
|
|
function getStatsOfType(connection, type)
|
|
{
|
|
return connection.getStats().then((report) => {
|
|
checkStatsReportIterator(report);
|
|
var stats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === type) {
|
|
stats = statItem;
|
|
}
|
|
});
|
|
return stats;
|
|
});
|
|
}
|
|
|
|
function testTimestampDifference(timeStampDifference, numberOfFrames)
|
|
{
|
|
// Let's ensure timestamp is not in microseconds but milliseconds.
|
|
return timeStampDifference > 100000 * (numberOfFrames / 30.0);
|
|
}
|
|
|
|
function checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, count)
|
|
{
|
|
return getInboundRTPStats(secondConnection).then((stats) => {
|
|
assert_true(!!stats.kind);
|
|
if (stats.framesDecoded > statsSecondConnection.framesDecoded) {
|
|
if (testTimestampDifference(stats.timestamp - statsSecondConnection.timestamp, stats.framesDecoded - statsSecondConnection.framesDecoded))
|
|
return Promise.reject("timestamp and frames increment do not match");
|
|
assert_not_equals(Object.keys(stats).indexOf("codecId"), -1, "codecId");
|
|
assert_not_equals(Object.keys(stats).indexOf("trackId"), -1, "trackId");
|
|
return;
|
|
}
|
|
if (++count === 20)
|
|
return Promise.reject("checking inbound stats frame number increasing timed out");
|
|
return waitFor(50).then(() => {
|
|
return checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, count)
|
|
});
|
|
});
|
|
}
|
|
|
|
function checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, count)
|
|
{
|
|
return getOutboundRTPStats(firstConnection).then((stats) => {
|
|
if (stats.framesEncoded > statsFirstConnection.framesEncoded) {
|
|
if (testTimestampDifference(stats.timestamp - statsFirstConnection.timestamp, stats.framesEncoded - statsFirstConnection.framesEncoded))
|
|
return Promise.reject("timestamp and frames increment do not match");
|
|
assert_not_equals(Object.keys(stats).indexOf("codecId"), -1, "codecId");
|
|
assert_not_equals(Object.keys(stats).indexOf("trackId"), -1, "trackId");
|
|
return;
|
|
}
|
|
if (++count === 20)
|
|
return Promise.reject("checking outbound stats frame number increasing timed out");
|
|
return waitFor(50).then(() => {
|
|
return checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, count)
|
|
});
|
|
});
|
|
}
|
|
|
|
var firstConnection, secondConnection;
|
|
promise_test(async (test) => {
|
|
if (window.testRunner)
|
|
testRunner.setUserMediaPermission(true);
|
|
|
|
const localStream = await navigator.mediaDevices.getUserMedia({ audio : true, video: true});
|
|
await new Promise((resolve, reject) => {
|
|
createConnections((connection) => {
|
|
firstConnection = connection;
|
|
firstConnection.addTrack(localStream.getAudioTracks()[0], localStream);
|
|
firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
|
|
}, (connection) => {
|
|
secondConnection = connection;
|
|
secondConnection.addTrack(localStream.getAudioTracks()[0], localStream);
|
|
secondConnection.addTrack(localStream.getVideoTracks()[0], localStream);
|
|
secondConnection.ontrack = (trackEvent) => {
|
|
resolve();
|
|
};
|
|
});
|
|
setTimeout(() => reject("Test timed out"), 5000);
|
|
});
|
|
|
|
let stats = await getOutboundRTPStats(firstConnection);
|
|
assert_true(!!stats, "outbound-rtp stats should not be null");
|
|
assert_true(Number.isInteger(stats.framesEncoded), "framesEncoded should be an integer");
|
|
assert_true(!stats.qpSum || Number.isInteger(stats.qpSum), "outbound qpSum should be an integer");
|
|
assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
|
|
statsFirstConnection = stats;
|
|
|
|
stats = await getInboundRTPStats(secondConnection);
|
|
assert_true(!!stats, "inbound-rtp stats should not be null");
|
|
assert_true(Number.isInteger(stats.framesDecoded), "framesDecoded should be an integer");
|
|
assert_true(!stats.qpSum || Number.isInteger(stats.qpSum), "inbound qpSum should be an integer");
|
|
assert_true(typeof stats.timestamp === "number", "timestamp should be a double");
|
|
statsSecondConnection = stats;
|
|
|
|
await checkInboundFramesNumberIncreased(secondConnection, statsSecondConnection, 0);
|
|
await checkOutboundFramesNumberIncreased(firstConnection, statsFirstConnection, 0);
|
|
|
|
let types;
|
|
do {
|
|
types = await getStatsType(firstConnection);
|
|
if (types.length != 12)
|
|
types = undefined;
|
|
} while(!types);
|
|
|
|
assert_array_equals(types, ["candidate-pair", "certificate", "codec", "inbound-rtp", "local-candidate", "media-source", "outbound-rtp", "peer-connection", "remote-candidate", "remote-inbound-rtp", "track", "transport"], "first connection");
|
|
|
|
do {
|
|
types = await getStatsType(secondConnection);
|
|
if (types.length != 12)
|
|
types = undefined;
|
|
} while(!types);
|
|
|
|
assert_array_equals(types, ["candidate-pair", "certificate", "codec", "inbound-rtp", "local-candidate", "media-source", "outbound-rtp", "peer-connection", "remote-candidate", "remote-inbound-rtp", "track", "transport"], "second connection");
|
|
|
|
const audioSourceStats = await getAudioSourceStats(firstConnection);
|
|
assert_true(!!audioSourceStats, "audio source presence");
|
|
|
|
const videoSourceStats = await getVideoSourceStats(firstConnection);
|
|
assert_true(!!videoSourceStats, "video source presence");
|
|
|
|
const remoteInboundStats = await getRemoteInboundRTPStats(firstConnection);
|
|
assert_true(remoteInboundStats.kind === "audio"|| remoteInboundStats.kind === "video", "kind is present");
|
|
}, "Basic video stats");
|
|
|
|
promise_test(async (test) => {
|
|
const report = await firstConnection.getSenders()[0].getStats();
|
|
checkStatsReportIterator(report);
|
|
var instats, outstats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === "outbound-rtp")
|
|
outstats = statItem;
|
|
else if (statItem.type === "inbound-rtp")
|
|
instats = statItem;
|
|
});
|
|
assert_true(!!outstats);
|
|
assert_false(!!instats);
|
|
}, "Sender stats");
|
|
|
|
promise_test(async (test) => {
|
|
const report = await secondConnection.getReceivers()[0].getStats();
|
|
checkStatsReportIterator(report);
|
|
var instats, outstats;
|
|
report.forEach((statItem) => {
|
|
if (statItem.type === "outbound-rtp")
|
|
outstats = statItem;
|
|
else if (statItem.type === "inbound-rtp")
|
|
instats = statItem;
|
|
});
|
|
assert_false(!!outstats);
|
|
assert_true(!!instats);
|
|
|
|
assert_greater_than_equal(instats.jitterBufferDelay, 0, "jitterBufferDelay");
|
|
assert_greater_than_equal(instats.jitterBufferEmittedCount, 0, "jitterBufferEmittedCount");
|
|
assert_greater_than_equal(instats.concealedSamples, 0, "concealedSamples");
|
|
assert_greater_than_equal(instats.totalSamplesReceived, 0, "totalSamplesReceived");
|
|
}, "Receiver stats");
|
|
|
|
promise_test(async (test) => {
|
|
const report = await secondConnection.getReceivers()[0].getStats();
|
|
let stats = await getStatsOfType(secondConnection, "transport");
|
|
|
|
assert_equals(stats.dtlsState, "connected");
|
|
assert_true(!!stats.dtlsCipher, "dtlsCipher");
|
|
assert_true(!!stats.srtpCipher, "srtpCipher");
|
|
assert_true(!!stats.tlsVersion, "tlsVersion");
|
|
assert_true(!!stats.bytesReceived, "bytesReceived");
|
|
assert_true(!!stats.bytesSent, "bytesSent");
|
|
}, "Transport stats");
|
|
|
|
promise_test(async (test) => {
|
|
let instats1, instats2;
|
|
|
|
let report1 = await secondConnection.getReceivers()[0].getStats();
|
|
report1.forEach((statItem) => {
|
|
if (statItem.type === "inbound-rtp")
|
|
instats1 = statItem;
|
|
});
|
|
waitFor(50);
|
|
let report2 = await secondConnection.getReceivers()[0].getStats();
|
|
report2.forEach((statItem) => {
|
|
if (statItem.type === "inbound-rtp")
|
|
instats2 = statItem;
|
|
});
|
|
assert_equals(instats1.ssrc, instats2.ssrc);
|
|
}, "Check ssrc is not changing in inbound rtp stats");
|
|
|
|
promise_test(async (test) => {
|
|
const pc = new RTCPeerConnection();
|
|
pc.close();
|
|
return pc.getStats();
|
|
}, "Stats after pc close");
|
|
</script>
|
|
</body>
|
|
</html>
|