ScaleDrone / webrtc

Video chat App with WebRTC using Scaledrone Realtime Messaging Service
https://www.scaledrone.com/
252 stars 205 forks source link

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

Open meghq opened 6 years ago

meghq commented 6 years ago

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 ); }

Pierre-Demessence commented 6 years ago

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.

kirusiya commented 5 years ago

i have same problem, how con i fixed

AlekRuzic commented 5 years ago

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

rawars commented 4 years ago

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: 'webrtc@live.com'
      }
  ]
}
const peerConnection = new RTCPeerConnection(config);

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

rsingh2083 commented 4 years ago

@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.

DanielNogueraDevelopment commented 4 years ago

Going to port 8080 worked for me!

rawars commented 4 years ago

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);

sehdev commented 4 years ago

@rawars how to deploy signaling server on port 8080?

rawars commented 4 years ago

@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);
});