blob: a2604ce3356982cf4557536b2eda8f7a4c4e799a [file] [log] [blame]
<!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("framesDropped" in 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 === 50)
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 === 50)
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");
assert_not_equals(remoteInboundStats.packetsLost, undefined);
}, "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>