0
votes

I am trying to use simple-peer library to broadcast a live video stream from the webcam to the server and from the server to multiple users. I am currently having problems with the stun/turn servers. I am using Xirsys. The program runs locally with no problems, but when I run it on Heroku it does not. I am new in NodeJs.

Does anyone know why it runs locally, but not globally?

Client side:

let Peer = require('simple-peer')
let socket = io()
const video = document.querySelector('video')
let client = {}

var configuration={
    iceServers: [{
        urls: [ "stun:sp-turn1.xirsys.com" ]
     }, {
        username: "LdzgXD2MWspU8qKuKIa9nYv02AqPhqD_qOeFSCsJfBjaCwq5mN-LsbrHReCmgGLwAAAAAF4HabRjYW1pbG9oaW5vam9zYQ==",
        credential: "320899dc-2980-11ea-810a-06374c00029e",
        urls: [
            "turn:sp-turn1.xirsys.com:80?transport=udp",
            "turn:sp-turn1.xirsys.com:3478?transport=udp",
            "turn:sp-turn1.xirsys.com:80?transport=tcp",
        ]
     }]
}

function CreateVideo(stream){
    video.srcObject = stream
    video.play()
}

document.getElementById('stream').onclick=function(){
    navigator.mediaDevices.getUserMedia({ video: true, audio: true })
    .then(stream=>{
        socket.emit('NewClientStreamer')
        video.srcObject = stream
        video.play()

        socket.on('CreateClientStreamerPeer',function(){
            let peer = new Peer({ 
                initiator:true,
                config:configuration,
                iceTransportPolicy: 'relay', 
                stream: stream, 
                trickle:true
            })
            peer.on('stream',function(stream){
                CreateVideo(stream)
            })
            peer.on('close',function(){
                document.getElementById("peerVideo").remove()
                peer.destroy()
            })
            peer.on('signal', function(data){
                if(!client.gotAnswer)
                    socket.emit('Offer',data)
            })
            client.peer=peer
        })

        socket.on('Answer',function(answer){
            client.gotAnswer=true
            client.peer.signal(answer)        
        })

    })
    .catch(err=>document.write(err))
}

document.getElementById('receive').onclick=function(){

    socket.emit('NewClientReceiver')

    socket.on('Offer',function(offer){
        let peer = new Peer({ 
            initiator: false,
            trickle:true
         })
        peer.on('stream',function(stream){
            CreateVideo(stream)
        })
        peer.on('signal', function(data){
            socket.emit('ClientAnswer',data)
        })
        peer.signal(offer)
        client.peer=peer
    })
}

Server side:

const express = require('express')
const app = express()
const http = require('http').Server(app)
const io = require('socket.io')(http)
const port = process.env.PORT || 3000

const Peer=require('simple-peer')
const wrtc=require('wrtc')

var Streamer={}
var Receiver={}



var configuration={
    iceServers: [{
        urls: [ "stun:sp-turn1.xirsys.com" ]
     }, {
        username: "LdzgXD2MWspU8qKuKIa9nYv02AqPhqD_qOeFSCsJfBjaCwq5mN-LsbrHReCmgGLwAAAAAF4HabRjYW1pbG9oaW5vam9zYQ==",
        credential: "320899dc-2980-11ea-810a-06374c00029e",
        urls: [
            "turn:sp-turn1.xirsys.com:80?transport=udp",
            "turn:sp-turn1.xirsys.com:3478?transport=udp",
            "turn:sp-turn1.xirsys.com:80?transport=tcp",
        ]
     }]
}

app.use(express.static(__dirname + "/public"))

io.on('connection', function(socket){

    socket.on('NewClientStreamer',function(){
        socket.emit('CreateClientStreamerPeer')
    })

    function InitializeReceiver(offer){
        var receiver={}
        let peer = new Peer({
            initiator:false,
            config:configuration,
            iceTransportPolicy: 'any',
            wrtc:wrtc,
            trickle:true
         })
        peer.on('signal', (data) => {
            socket.emit('Answer',data)
        })
        peer.on('close',function(){
            //
        })
        peer.on('stream',function(stream){
            receiver.stream=stream
            receiver.peer=peer
            Receiver=receiver
        })
        peer.signal(offer)
    }

    socket.on('Offer',function(offer){
        InitializeReceiver(offer)
    })

    socket.on('NewClientReceiver',function(){
        var streamer={}
        streamer.gotAnswer=false
        let peer = new Peer({
            initiator:true,
            config:configuration,
            iceTransportPolicy: 'any',
            wrtc:wrtc,
            stream: Receiver.stream, 
            trickle:true
        })
        peer.on('signal', function(offer){
            if(!streamer.gotAnswer)
                socket.emit('Offer',offer)
        })
        peer.on('connect',function(){
            Streamer=streamer
        })
        streamer.peer=peer

        socket.on('ClientAnswer',function(data){    
            streamer.gotAnswer=true
            streamer.peer.signal(data)  
        })
    })




})

http.listen(port,() => console.log(`Active on ${port} port`))

WebRTC-Chrome-webRTC internals

3
Can you please provide/attach dump from chrome://webrtc-internals/? - Igor Khvostenkov
Igor Khvostenkov, thank you for your reply. I have added a screenshot of my webrtc-internals. - Camilo Hinojosa
If the screenshot is not enough. Here is a link to the heroku app: bolxmultitest.herokuapp.com - Camilo Hinojosa

3 Answers

0
votes

So the answer to your initial question: why it runs locally and does not run on the server is: this happens due to running locally you either run server and client in the same network or thru simple NAT and STUN server can solve your client and server external IPs. When you run on the server either your server or the client is behind the double NAT or Symmetric NAT. Based on your code this should be not a problem, due to your configured TURN server, but if you look in your WebRTC stats this configuration is not applied, some other configuration is used, see screenshot. When I run it from my computer no TURN server is configured at all, and obviously my IP address is not resolved, as I am behind the double NAT and connection failed, see my logs:

https://bolxmultitest.herokuapp.com/, { iceServers: [stun:stun.l.google.com:19302, stun:global.stun.twilio.com:3478?transport=udp], iceTransportPolicy: all, bundlePolicy: balanced, rtcpMuxPolicy: require, iceCandidatePoolSize: 0, sdpSemantics: "unified-plan" },
iceconnectionstatechange (legacy)
checking
03/01/2020, 16:10:42    
connectionstatechange
connecting
03/01/2020, 16:10:42    
icecandidate (host)
sdpMid: 0, sdpMLineIndex: 0, candidate: candidate:1416191245 1 udp 2113937151 cb0baca2-665d-45a9-9c92-5fd0accdbb0f.local 51937 typ host generation 0 ufrag 9Gjl network-cost 999
03/01/2020, 16:10:42    
icecandidate (srflx)
sdpMid: 0, sdpMLineIndex: 0, candidate: candidate:842163049 1 udp 1677729535 37.24.130.114 51937 typ srflx raddr 0.0.0.0 rport 0 generation 0 ufrag 9Gjl network-cost 999
03/01/2020, 16:10:42    
icegatheringstatechange
complete
03/01/2020, 16:10:57    
iceconnectionstatechange
disconnected
03/01/2020, 16:10:57    
iceconnectionstatechange (legacy)
failed
03/01/2020, 16:10:57    
connectionstatechange
failed

STUN/TURN configuration should looked similar to this in the logs, as this is configure in your code above:

{ iceServers: [stun:sp-turn1.xirsys.com:3478, turns:sp-turn1.xirsys.com:443?transport=tcp], iceTransportPolicy: all, bundlePolicy: balanced, rtcpMuxPolicy: require, iceCandidatePoolSize: 0, sdpSemantics: "unified-plan" }

You need to debug why configuration from your code is not applied and why you and I have different configuration and where does this configuration come from.

enter image description here

0
votes

I have detected the problem why my credentials were not the same as the code, it was because I had forgotten to run watchify to modify the bundle.js script based on the main.js

These are my new webRTC chrome internals. Now the credentials match, but it still does not run. Thank you, Igor Khvostenkov.

This is the link to the app running the new repo: https://bolx-tests.herokuapp.com/

0
votes

You fixed STUN/TURN server problem on the server for stream from client to server, but you need to fix this problem on the client-side as well. If you look in the logs while trying to receive stream you will see a enter image description heredifferent configuration of the STUN/TURN servers from what you have in your code.