0

I am trying to create a P2P chat file in Firefox using WebRTC, but I have so far been unsuccessful in finding any working examples or in modifying any of the examples that I have found to work between different computers on different networks. The examples that I have found work only on a single computer, or on two computers within the same network. I am looking for an example where I can do the following:

  1. User 1 initiates the connection by pressing the start button, which generates a session description and gives it to them. They then email this session description to User 2.

  2. User 2 pastes the session description from User 1 into a textarea and receives a second session description in response. User 2 then emails this second session description back to User 1.

  3. User 1 pastes the second session description from User 2 into a textarea, which completes the connection.

  4. The session now completed, both users can chat back and forth.

Eventually, my aim is to accomplish the session description transfer through a centralized server, but I want to establish this method as a proof-of-concept first, because if I cannot get this to work, then I would rather not have spent the time on the server bit.

These two examples are pretty much what I want to do, but they only appear to work on a single computer:

https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Simple_RTCDataChannel_sample

https://webrtc.github.io/samples/src/content/datachannel/basic/

This example is exactly what I want to do, but it is 7 years old and does not appear to work anymore:

https://cjb.github.io/serverless-webrtc/serverless-webrtc.html

Here is my adaptation of Mozilla's example file above that I am testing out:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        body {
            font-family: "Lucida Grande", "Arial", sans-serif;
            font-size: 16px;
        }

        .messagebox {
            border: 1px solid black;
            padding: 5px;
            width: 450px;
        }

        .buttonright {
            float: right;
        }

        .buttonleft {
            float: left;
        }

        .controlbox {
            padding: 5px;
            width: 450px;
            height: 28px;
        }
    </style>
    <script>

        var initiateConnectionButton = null;
        var getAnswerButton = null;
        var completeConnectionButton = null;
        var disconnectButton = null;
        var sendButton = null;
        var messageInputBox = null;
        var receiveBox = null;

        var localConnection = null;

        var sendChannel = null;
        var receiveChannel = null;

        var constraints = null;

        var configuration = {
            iceServers: [
                {
                    urls: 'stun:stun.l.google.com:19302'
                }
            ]
        };          

        function handleSendChannelStatusChange(event) {
            return;
        }

        function handleReceiveChannelStatusChange(event) {
            return;
        }

        window.addEventListener('load', function () {

            initiateConnectionButton = document.getElementById('initiate-connection-button');
            getAnswerButton = document.getElementById('get-answer-button');
            completeConnectionButton = document.getElementById('complete-connection-button');
            disconnectButton = document.getElementById('disconnect-button');
            sendButton = document.getElementById('sendButton');
            messageInputBox = document.getElementById('message');
            receiveBox = document.getElementById('receivebox');

            initiateConnectionButton.addEventListener('click', function () {

                localConnection = new RTCPeerConnection();

                sendChannel = localConnection.createDataChannel("sendChannel");
                sendChannel.onopen = handleSendChannelStatusChange;
                sendChannel.onclose = handleSendChannelStatusChange;

                localConnection.createOffer()
                .then(function(offer) {
                    console.log(JSON.stringify(offer));
                    localConnection.setLocalDescription(offer);
                })
                .catch(function(error) {
                    console.log("Unable to create an offer: " + error.toString());
                });

            }, false);

            getAnswerButton.addEventListener('click', function () {

                localConnection = new RTCPeerConnection(configuration);

                sendChannel = localConnection.createDataChannel("sendChannel");
                sendChannel.onopen = handleSendChannelStatusChange;
                sendChannel.onclose = handleSendChannelStatusChange;

                localConnection.onicecandidate = function(e) {
                    localConnection.addIceCandidate(e.candidate);
                    // if (e.candidate && e.candidate['candidate'].includes("TCP")) {
                    //  localConnection.addIceCandidate(e.candidate);
                    // }
                }

                let sessionDescription = new RTCSessionDescription(JSON.parse(document.getElementById("local-description-input").value));
                localConnection.setRemoteDescription(sessionDescription)
                .then(function() {
                    answer = localConnection.createAnswer();
                })
                .then(function(answer) {
                    console.log(answer);
                    let result =  localConnection.setLocalDescription(answer);
                    return result;
                })
                .catch(function(error) {
                    console.log("Error: " + error.toString());
                });

            }, false);

            completeConnectionButton.addEventListener('click', function () {

                localConnection.ondatachannel = function (event) {

                    receiveChannel = event.channel;
                    receiveChannel.onmessage = function(event) {
                        var el = document.createElement("p");
                        var txtNode = document.createTextNode(event.data);
                        el.appendChild(txtNode);
                        receiveBox.appendChild(el);
                    };
                    receiveChannel.onopen = handleReceiveChannelStatusChange;
                    receiveChannel.onclose = handleReceiveChannelStatusChange;

                };

                localConnection.onicecandidate = function(e) {
                    if (e.candidate && e.candidate['candidate'].includes("tcp")) {
                        console.log(e.candidate);
                        localConnection.addIceCandidate(e.candidate);
                    }
                }

                let sessionDescription = new RTCSessionDescription({
                    type: "answer",
                    sdp: atob(document.getElementById("remote-description-input").value)
                });                 
                localConnection.setRemoteDescription(sessionDescription);
                console.log(localConnection);

            }, false);

            disconnectButton.addEventListener('click', function () {

                // Close the RTCDataChannels if they're open.

                sendChannel.close();
                receiveChannel.close();

                // Close the RTCPeerConnections

                localConnection.close();

                sendChannel = null;
                receiveChannel = null;
                localConnection = null;

            }, false);

            sendButton.addEventListener('click', function() {
                var message = messageInputBox.value;
                sendChannel.send(message);
                messageInputBox.value = "";
                messageInputBox.focus();
            }, false);

        }, false);

    </script>
</head>
<body>

    <div class="controlbox">
        <button id="disconnect-button">
            Disconnect
        </button>
    </div>

    <div class="messagebox">
        <label for="message">Enter a message:
            <input type="text" name="message" id="message" placeholder="Message text" 
            inputmode="latin" size=60 maxlength=120>
        </label>
        <button id="sendButton" name="sendButton" class="buttonright">
            Send
        </button>
    </div>
    <div class="messagebox" id="receivebox">
        <p>Messages received:</p>
    </div>

    <h2>Initiate Connection</h2>
    <button id="initiate-connection-button">
        Initiate Connection
    </button>

    <h2>Get Answer</h2>
    <textarea id="local-description-input"></textarea>
    <button id="get-answer-button">Get Answer</button>

    <h2>Complete Connection</h2>
    <textarea id="remote-description-input"></textarea>
    <button id="complete-connection-button">Submit</button>

</body>

</html>

Here is the about:webrtc error log that I get after I attempt to connect:

(generic/EMERG) Exit UDP socket connected

(generic/ERR) UDP socket error:Internal error at /builds/worker/checkouts/gecko/dom/network/UDPSocketParent.cpp:268 this=00000258866EA000

(ice/INFO) /builds/worker/checkouts/gecko/media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c:173 function nr_socket_multi_tcp_create_stun_server_socket skipping UDP STUN server(addr:)

(ice/WARNING) /builds/worker/checkouts/gecko/media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c:617 function nr_socket_multi_tcp_listen failed with error 3

(ice/WARNING) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): failed to create passive TCP host candidate: 3

(ice/WARNING) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): peer (PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html):default) has no stream matching stream PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html) transport-id=transport_0 - 18a9322f:167fe60f30b26ec3c9fd8ab65febec08

(ice/NOTICE) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): peer (PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html):default) no streams with non-empty check lists

(ice/NOTICE) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): peer (PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html):default) no streams with pre-answer requests

(ice/NOTICE) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): peer (PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html):default) no checks to start

(ice/ERR) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): peer (PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html):default) pairing local trickle ICE candidate host(IP4:173.17.64.254:58401/UDP)

(ice/ERR) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): peer (PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html):default) pairing local trickle ICE candidate host(IP4:173.17.64.254:59370/TCP) active

(stun/INFO) STUN-CLIENT(srflx(IP4:173.17.64.254:58401/UDP|stun.l.google.com:19302)): Received response; processing

(ice/INFO) ICE(PC:1586652270128000 (id=2147483682 url=file:///C:/Users/root/Desktop/webrtc/index2.html)): All candidates initialized

+++++++ END ++++++++

kloddant
  • 35
  • 5
  • do you get any errors in your attempt? – Jaromanda X Apr 12 '20 at 00:07
  • what's the connection procedure with your page? – Jaromanda X Apr 12 '20 at 00:15
  • The connection procedure with my page is that I first open the file in two separate browsers. I have been using Firefox and Firefox Developer for this. I press the Initiate Connection button. This causes the json encoded session description to appear in the console. I copy this to the "Get Answer" textarea of the second window and press the button, after which two errors appear in the console: Unknown ufrag and ICE failed, add a TURN server and see about:webrtc for more details. I am not sure why it should be requiring a TURN server, so I am thinking that something I am doing is wrong. – kloddant Apr 12 '20 at 00:28
  • I did try creating a TURN server on an EC2 instance earlier today and adding that as another ICE server in the list. Then I got a different error message, something like "There was an error with your TURN server." So I was working on the config for that. But then I found out that you only really need a TURN server as a fallback, so I shut it down, because since this is just a side project, I don't really need it to be 100% reliable, just to work most of the time and I don't really want to have to route all the traffic through a server. – kloddant Apr 12 '20 at 00:31
  • Also, theoretically, after I press the "Get Answer" button, if the error did not happen, it would give me back the json encoded session description of the 2nd window, after which I would paste that back into the "Complete Connection" box of the 1st window. Then I would sent messages between the windows. Theoretically. Haven't seen what actually happens after the step I am stuck on though. – kloddant Apr 12 '20 at 00:35
  • have you checked the logs in `about:webrtc` – Jaromanda X Apr 12 '20 at 00:42
  • Yup, but unfortunately I am new to this and do not know how to interpret the results. I'll post them at the bottom of the question though. – kloddant Apr 12 '20 at 00:45
  • oh ... are you not using `https://` for this? you're using `file:///` protocol? – Jaromanda X Apr 12 '20 at 00:49
  • Correct, though I could try running a local server if you think that would help. Let me just try that and see. – kloddant Apr 12 '20 at 00:54
  • I always thought webrtc needed HTTPS (note, the S, not HTTP) - I could be wrong though – Jaromanda X Apr 12 '20 at 00:57
  • I am reading that it is supposed to work on http with the specific hostname localhost, so I tried it on a server running on localhost:8000, but it still did not work. Tomorrow I'll try uploading it to an actual https site just to be sure. – kloddant Apr 12 '20 at 01:16
  • You can look into this link https://codesandbox.io/s/video-chat-webrtc-m2grv?fontsize=14&hidenavigation=1&theme=dark – Serdar Apr 12 '20 at 09:05
  • From your comments, it looks like you already try to set up using a turn server. You can test your code by using https://numb.viagenie.ca/ as a free test-turn-server. To check if your own server is working, the snippet https://stackoverflow.com/a/34033938/5025161 has been helpful for me – nasskalte.juni Apr 16 '20 at 15:32

0 Answers0