webrtc icon indicating copy to clipboard operation
webrtc copied to clipboard

DOMException: Failed to set local answer sdp: Called in wrong state: kStable

Open meghq opened this issue 6 years ago • 9 comments

I am trying to run the webRTC code which i have mentioned below, it is working fine when i am connecting with two devices using same network. But it is not connecting when the devices are in different networks and i am getting DOM Exception. please help me to fix it.

// Generate random room name if needed if (!location.hash) { location.hash = Math.floor(Math.random() * 0xFFFFFF).toString(16); } const roomHash = location.hash.substring(1);

// TODO: Replace with your own channel ID const drone = new ScaleDrone('yiS12Ts5RdNhebyM'); // Room name needs to be prefixed with 'observable-' const roomName = 'observable-' + roomHash; const configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }; let room; let pc;

function onSuccess() {}; function onError(error) { console.error(error); };

drone.on('open', error => { if (error) { return console.error(error); } room = drone.subscribe(roomName); room.on('open', error => { if (error) { onError(error); } }); // We're connected to the room and received an array of 'members' // connected to the room (including us). Signaling server is ready. room.on('members', members => { console.log('MEMBERS', members); // If we are the second user to connect to the room we will be creating the offer const isOfferer = members.length === 2; startWebRTC(isOfferer); }); });

// Send signaling data via Scaledrone function sendMessage(message) { drone.publish({ room: roomName, message }); }

function startWebRTC(isOfferer) { pc = new RTCPeerConnection(configuration);

// 'onicecandidate' notifies us whenever an ICE agent needs to deliver a // message to the other peer through the signaling server pc.onicecandidate = event => { if (event.candidate) { sendMessage({'candidate': event.candidate}); } };

// If user is offerer let the 'negotiationneeded' event create the offer if (isOfferer) { pc.onnegotiationneeded = () => { pc.createOffer().then(localDescCreated).catch(onError); } }

// When a remote stream arrives display it in the #remoteVideo element pc.ontrack = event => { const stream = event.streams[0]; if (!remoteVideo.srcObject || remoteVideo.srcObject.id !== stream.id) { remoteVideo.srcObject = stream; } };

navigator.mediaDevices.getUserMedia({ audio: true, video: true, }).then(stream => { // Display your local video in #localVideo element localVideo.srcObject = stream; // Add your stream to be sent to the conneting peer stream.getTracks().forEach(track => pc.addTrack(track, stream)); }, onError);

// Listen to signaling data from Scaledrone room.on('data', (message, client) => { // Message was sent by us if (client.id === drone.clientId) { return; }

if (message.sdp) {
  // This is called after receiving an offer or answer from another peer
  pc.setRemoteDescription(new RTCSessionDescription(message.sdp), () => {
    // When receiving an offer lets answer it
    if (pc.remoteDescription.type === 'offer') {
      pc.createAnswer().then(localDescCreated).catch(onError);
    }
  }, onError);
} else if (message.candidate) {
  // Add the new ICE candidate to our connections remote description
  pc.addIceCandidate(
    new RTCIceCandidate(message.candidate), onSuccess, onError
  );
}

}); }

function localDescCreated(desc) { pc.setLocalDescription( desc, () => sendMessage({'sdp': pc.localDescription}), onError ); }

meghq avatar Sep 26 '18 13:09 meghq

Hello,

As far as I know, the issues comes from Chrome Desktop who's sending the request twice. Using another browser fixed the issue for me.

Pierre-Demessence avatar Oct 17 '18 20:10 Pierre-Demessence

i have same problem, how con i fixed

kirusiya avatar Dec 03 '18 05:12 kirusiya

I currently have the exact same problem, I'll try using a different browser when I get a chance to test across different networks again

AlekRuzic avatar Sep 13 '19 19:09 AlekRuzic

Dude, I had the same problem and you can fix it by deploying the signaling server on port 8080.

Also I had to add these iceServers:

const config = {
  'iceServers': [
      { url: 'stun:stun1.l.google.com:19302' },
      {
          url: 'turn:numb.viagenie.ca',
          credential: 'muazkh',
          username: '[email protected]'
      }
  ]
}
const peerConnection = new RTCPeerConnection(config);

I managed to deploy with the fixes on an amazon server.

rawars avatar Apr 15 '20 22:04 rawars

@rawars How do I deploy it on port 8080 ? Where is the option to change port ? Im running on my localhost desktop and trying to connect to it from laptop.

rsingh2083 avatar Apr 17 '20 08:04 rsingh2083

Going to port 8080 worked for me!

Hello, for those who still do not work even changing the port to 8080, it is because they need to go through the configuration, the ice servers:

const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]} const peerConnection = new RTCPeerConnection(configuration);

rawars avatar May 24 '20 15:05 rawars

@rawars how to deploy signaling server on port 8080?

sehdev avatar Jun 10 '20 13:06 sehdev

@rawars how to deploy signaling server on port 8080?

In Amazon lightsail:

const express = require('express');
const socketIO = require('socket.io');

const http = require('http');
const https = require('https');
const path = require('path');
const fs = require('fs');

var PatientsSockets = [];
var DoctorsSockets = [];

const DEFAULT_PORT = 8080;

const app = express()

var Server = null;

Server = https.createServer({
    key: fs.readFileSync('/etc/letsencrypt/live/domain.com/privkey.pem'),
    cert: fs.readFileSync('/etc/letsencrypt/live/domain.com/fullchain.pem'),
}, app);

var io = socketIO(Server);

app.use(express.static(path.join(__dirname, "public")));

io.on("connection", socket => {

    socket.on("new-paciente", (data) => {
        const existingSocket = PatientsSockets.find(existingSocket => existingSocket.socket === socket.id);
        if (!existingSocket) {

            PatientsSockets.push({
                names: data.names,
                surnames: data.surnames,
                socket: socket.id,
                role: 'PATIENT'
            });
            socket.broadcast.emit("update-list-patients", {
                patients: PatientsSockets
            });

        }
    });

    socket.on("new-doctor", (data) => {
        const existingSocket = DoctorsSockets.find(existingSocket => existingSocket.socket === socket.id);
        if (!existingSocket) {
            DoctorsSockets.push({
                socket: socket.id,
                role: 'DOCTOR'
            });
        }
    });

    socket.on("make-answer", data => {
        socket.to(data.to).emit("answer-made", {
            socket: socket.id,
            answer: data.answer
        });
    });

    socket.on("call-patient", (data) => {
        socket.to(data.to).emit("notify-call", {
            offer: data.offer,
            socket: socket.id
        });
    });

    socket.on("load-patients", (data) => {
        socket.emit("update-list-patients", {
            patients: PatientsSockets
        });
    });

    socket.on("disconnect", () => {
        PatientsSockets = PatientsSockets.filter(existingSocket => existingSocket.socket !== socket.id);
        socket.broadcast.emit("remove-user", {
            disconnected: socket.id,
            patients: PatientsSockets
        });
    });
});

Server.listen(DEFAULT_PORT, () => {
    console.log('HTTPS Server running on port ' + DEFAULT_PORT);
});

rawars avatar Jun 16 '20 16:06 rawars