<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
    <head>
        <script src="../../resources/js-test-pre.js"></script>
        <script src="resources/promise-utils.js"></script>
    </head>
    <body>
        <script>
            let stream;
            let offer;

            description("Test setting up media between two RTCPeerConnection instances with a single SDP dialog.");

            if (!window.testRunner) {
                debug("This test can not be run without the testRunner");
                finishJSTest();
            }

            debug("Create RTCPeerConnection A");
            const pcA = new RTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]});

            shouldBe("pcA.signalingState", "'stable'");
            shouldBeNull("pcA.pendingLocalDescription");
            shouldBeNull("pcA.currentLocalDescription");
            shouldBeNull("pcA.pendingRemoteDescription");
            shouldBeNull("pcA.currentRemoteDescription");

            debug("<br>Create RTCPeerConnection B");
            const pcB = new RTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]});

            shouldBe("pcB.signalingState", "'stable'");
            shouldBeNull("pcB.pendingLocalDescription");
            shouldBeNull("pcB.currentLocalDescription");
            shouldBeNull("pcB.pendingRemoteDescription");
            shouldBeNull("pcB.currentRemoteDescription");
            debug("");

            pcA.ontrack = function () {
                debug("----------");
                testPassed("A: got remote track event");
                debug("----------");
            };

            pcB.ontrack = function () {
                debug("----------");
                testPassed("B: got remote track event");
                debug("----------");
            };

            navigator.mediaDevices.getUserMedia({ "audio": true })
            .then(function (s) {
                stream = s;

                debug("A: add media");
                pcA.addTrack(stream.getAudioTracks()[0], stream);

                debug("A: create offer");
                return pcA.createOffer();
            })
            .then(function (offer) {
                debug("A: got offer, set it as local description");
                return pcA.setLocalDescription(offer);
            })
            .then(function () {
                debug("A: local offer set");
                shouldBe("pcA.signalingState", "'have-local-offer'");
                shouldBeType("pcA.pendingLocalDescription", "RTCSessionDescription");
                shouldBeNull("pcA.currentLocalDescription");

                debug("<br>A: send offer to B");
                debug("A --- offer --> B");
                debug("B: got offer from A, set it as remote description");
                return pcB.setRemoteDescription(pcA.localDescription);
            })
            .then(function () {
                debug("B: remote offer set");
                shouldBe("pcB.signalingState", "'have-remote-offer'");
                shouldBeType("pcB.pendingRemoteDescription", "RTCSessionDescription");
                shouldBeNull("pcB.currentRemoteDescription");

                debug("<br>B: create answer (without local media)");
                return pcB.createAnswer();
            })
            .then(function (answer) {
                debug("B: got answer, set it as local description");
                return pcB.setLocalDescription(answer);
            })
            .then(function () {
                debug("B: local answer set");
                shouldBe("pcB.signalingState", "'stable'");
                shouldBeNull("pcB.pendingLocalDescription");
                shouldBeType("pcB.currentLocalDescription", "RTCSessionDescription");
                shouldBeNull("pcB.pendingRemoteDescription");
                shouldBeType("pcB.currentRemoteDescription", "RTCSessionDescription");

                debug("<br>B: send answer to A");
                debug("A <-- answer -- B");
                debug("A: got answer from B, set it as remote description");
                return pcA.setRemoteDescription(pcB.localDescription);
            })
            .then(function () {
                debug("A: remote answer set");
                shouldBe("pcA.signalingState", "'stable'");
                shouldBeNull("pcA.pendingLocalDescription");
                shouldBeType("pcA.currentLocalDescription", "RTCSessionDescription");
                shouldBeNull("pcA.pendingRemoteDescription");
                shouldBeType("pcA.currentRemoteDescription", "RTCSessionDescription");
                debug("");

                testPassed("First offer/answer dialog completed")
                debug("========================================<br>")

                shouldBe("pcB.getSenders().length", "1");
                debug("B: add media (should reuse sender)");
                pcB.addTrack(stream.getAudioTracks()[0], stream);
                shouldBe("pcB.getSenders().length", "1");

                debug("B: create offer");
                return pcB.createOffer();
            })
            .then(function (offer) {
                debug("B: got offer, set it as local description");
                return pcB.setLocalDescription(offer);
            })
            .then(function () {
                debug("B: local offer set (session update so we have both pending and current local descriptions)");
                shouldBe("pcB.signalingState", "'have-local-offer'");
                shouldBeType("pcB.pendingLocalDescription", "RTCSessionDescription");
                shouldBeType("pcB.currentLocalDescription", "RTCSessionDescription");

                debug("<br>B: send offer to A");
                debug("A <-- offer --- B");
                debug("A: got offer from B, set it as remote description");
                return pcA.setRemoteDescription(pcB.localDescription);
            })
            .then(function () {
                debug("A: remote offer set (session update so we have both pending and current remote descriptions)");
                shouldBe("pcA.signalingState", "'have-remote-offer'");
                shouldBeType("pcA.pendingRemoteDescription", "RTCSessionDescription");
                shouldBeType("pcA.currentRemoteDescription", "RTCSessionDescription");

                debug("<br>A: create answer");
                return pcA.createAnswer();
            })
            .then(function (answer) {
                debug("A: got answer, set it as local description");
                return pcA.setLocalDescription(answer);
            })
            .then(function () {
                debug("A: local answer set");
                shouldBe("pcA.signalingState", "'stable'");
                shouldBeNull("pcA.pendingLocalDescription");
                shouldBeType("pcA.currentLocalDescription", "RTCSessionDescription");
                shouldBeNull("pcA.pendingRemoteDescription");
                shouldBeType("pcA.currentRemoteDescription", "RTCSessionDescription");

                debug("<br>A: send answer to B");
                debug("A --- answer -> B");
                debug("B: got answer from A, set it as remote description");
                return pcB.setRemoteDescription(pcA.localDescription);
            })
            .then(function () {
                debug("B: remote answer set");
                shouldBe("pcB.signalingState", "'stable'");
                shouldBeNull("pcB.pendingLocalDescription");
                shouldBeType("pcB.currentLocalDescription", "RTCSessionDescription");
                shouldBeNull("pcB.pendingRemoteDescription");
                shouldBeType("pcB.currentRemoteDescription", "RTCSessionDescription");
                debug("");

                testPassed("Second offer/answer dialog completed")
                debug("");

                finishJSTest();
            })
            .catch(function (error) {
                testFailed("Error in promise chain: " + error);
                finishJSTest();
            });

            window.jsTestIsAsync = true;
            window.successfullyParsed = true;

        </script>
        <script src="../../resources/js-test-post.js"></script>
    </body>
</html>
