<!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 getInboundRTPStats(connection)
{
    return connection.getStats().then((report) => {
        checkStatsReportIterator(report);
        var stats;
        report.forEach((statItem) => {
            if (statItem.type === "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 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) => {
        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({ video: true});
    await new Promise((resolve, reject) => {
        createConnections((connection) => {
            firstConnection = connection;
            firstConnection.addTrack(localStream.getVideoTracks()[0], localStream);
        }, (connection) => {
            secondConnection = connection;
            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(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(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 = await getStatsType(firstConnection);
    assert_array_equals(types, ["candidate-pair", "certificate", "codec", "inbound-rtp", "local-candidate", "outbound-rtp", "peer-connection", "remote-candidate", "track", "transport"]);

    types = await getStatsType(secondConnection);
    assert_array_equals(types, ["candidate-pair", "certificate", "codec", "inbound-rtp", "local-candidate", "outbound-rtp", "peer-connection", "remote-candidate", "track", "transport"]);
}, "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);
}, "Receiver 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");
        </script>
    </body>
</html>
