GithubHelp home page GithubHelp logo

scaledrone / webrtc Goto Github PK

View Code? Open in Web Editor NEW
246.0 14.0 205.0 6 KB

Video chat App with WebRTC using Scaledrone Realtime Messaging Service

Home Page: https://www.scaledrone.com/

HTML 27.38% JavaScript 72.62%
webrtc video-chat scaledrone javascript

webrtc's Introduction

webrtc's People

Contributors

atefbb avatar herkyl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webrtc's Issues

error

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

Demo no longer working with Safari

I've tried to connect from Safari to Chrome and vice versa.

If Safari is the initial member Safari give an error;
Unhandled Promise Rejection: InvalidStateError: Description type incompatible with current signaling state

If Chrome is the initial member, then Chrome's error is
DOMException: Error processing ICE candidate

I have had this working for a project in the past but can't see what the issue is

Add a Mute/Unmute Button?

I added the following code (i found online) to add a mute/unmute button and it doesnt work. Any idea why?

In index.html i added:
<button id="mute_btn" onclick="muteBtnClick()">Mute Mic</button>

In script.js i added at the very bottom:

function muteBtnClick() {
    var btn = document.getElementById("mute_btn");
     if (isMicMuted()) {
        muteMic(false);
            btn.innerHTML = "Mute Mic";
     } else {
     muteMic(true);
            btn.innerHTML = "Unmute Mic";
     }
}

function isMicMuted() {
     return !(localStream.getAudioTracks()[0].enabled); }

function muteMic (mute) {
     localStream.getAudioTracks()[0].enabled = !mute;
};

TrackStartError

open the live demo in chrome, can't work, find error in chrome devTool

image

How to add end stream function ??

everything is working great i want to add a function for end stream if user one is end stream it should be disconnect from both side.

not support all browser

We have integrate this code but only support Mozilla Firefox,but not support rest all of these browser please suggest for supporting all browser.

more than 2 users

Hi I am trying to have more than 2 users in the video chat? I've tried to dynamically add new videos, but the webrtc tends to error out. Do you have any resources I can look at to refactor this code? Thanks.

Not working on chrome and safari

I am trying to run this example with Chrome of window 10 and Safari 11 of iPad, but it's not working.

Each browser has displaying only local stream not remote one.

There is no issue on browsers because this demo is working on same.

Safari and iPads require Promise-based API for WebRTC

I'm posting this here in hopes it'll be useful to others. This project seems old and not updated anymore.

I built a chat room and referenced this code, and it worked fine in Firefox/Chromium on everything except for iPads or Safari browsers. I've made some progress in resolving why.

The most important change needed is that Safari only supports the modern Promise-based syntax for the WebRTC APIs whereas this project is using callbacks.

e.g.: instead of setLocalDescription(desc, onSuccess, onFailure) change those to setLocalDescription(desc).then(onSuccess).catch(onFailure) and Safari makes more progress.

Symptoms I noticed (my logic was closely inspired by this webrtc demo's, so this is probably true of this project still too):

  • When the offerer begins to connect, it should send SDP messages first and then send candidates.
  • However, iPad was sending candidates first and never SDP messages.
  • The recipient of those candidates (Firefox) would throw an error that candidates can't be added with no remoteDescription set.

The culprit was: the sendOffer() and then setLocalDescription logic was failing on Safari and the SDP message was not being sent. Firefox and Chrome supported the legacy APIs and worked OK, but Safari, being later to the WebRTC bandwagon, only opted to support the Promise-based APIs.

I also found this web page to be a valuable resource: https://webrtchacks.com/guide-to-safari-webrtc/

An important aspect of iPad is they seem to not support send-only or receive-only channels: it needs to be a bidirectional video call. I think this webrtc demo should be doing that OK: on the initial offer the iPad needs to attach their own local video channel to the call to begin with, and receive video from the answerer and then all works OK.

Trying to convert the script to use async/await

Hello, I am trying to integrate this code in my app where I am trying to pass the streams to my modules which hold the canvas elements.

I tried using async/await but unfortunately I am getting below error:

export default function getDrone() {
  return new Promise((resolve, reject) => {
    const drone = new Scaledrone('fBAkzbVAOmA2wbU0');
    const roomName = 'observable-room';
    const configuration = {
      iceServers: [
        {
          urls: 'stun:stun.l.google.com:19302'
        }
      ]
    };
    let room;
    let pc;
    const streamArr = [];

    async function handleError(error) {
      window.console.error(error);
      drone.close();
      reject(error);
    }

   
    async function handleClose() {
      window.console.log('Drone disconnected');
    }

    async function handleSuccess() {
      window.console.log('Drone connected');

      // window.console.log(drone);
    }

    async function handleRoom(error) {
      if (error) {
        handleError(error);
      }
      handleSuccess();
    }

    async function handleOpen(error) {
      if (error) {
        handleError(error);
      }

      window.console.log('Drone connecting');
      try {
        room = await drone.subscribe(roomName);
        room.on('open', handleRoom);
        room.on('members', handleMembers);
      } catch (e) {
        handleError(new Error('Failed to subscribe to room'));
      }
    }

    // Send signaling data via Scaledrone
    function sendMessage(message) {
      drone.publish({
        room: roomName,
        message
      });
    }
    function localDescCreated(desc) {
      pc.setLocalDescription(desc, () => sendMessage({ sdp: pc.localDescription }), handleError);
    }

    async function startWebRTC(isOfferer) {
      let remoteStream;
      let sourceStream;
      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
      var isNegotiating = false;
      if (isOfferer) {
        pc.onnegotiationneeded = () => {
          console.log('creating offer');
          if (isNegotiating) {
            console.log('Skiping nested negotiation');
            return;
          }
          isNegotiating = true;
          pc.createOffer()
            .then(localDescCreated)
            .catch(handleError);
        };
      }
      pc.onsignalingstatechange = e => {
        // Workaround for Chrome: skip nested negotiations
        isNegotiating = pc.signalingState !== 'stable';
      };
      pc.oniceconnectionstatechange = e => {
        // Workaround for Chrome: skip nested negotiations

        console.log('state change:', e, e.currentTarget.remoteDescription.sdp);
      };

      // When a remote stream arrives display it in the #remoteVideo element
      pc.ontrack = event => {
        const stream = event.streams[0];
    
        remoteStream = stream;
        streamArr.push(remoteStream);
      };

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

      // 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(handleError);
              }
            },
            handleError
          );
        } else if (message.candidate) {
          // Add the new ICE candidate to our connections remote description
          pc.addIceCandidate(new RTCIceCandidate(message.candidate), onSuccess, handleError);
        }
      });
    }
    async function onSuccess() {
      resolve(streamArr); //return streams array here back to my module.
      console.log('success');
    }

// I am getting 13 success output and also list of streams but connection is closed and also below error

    async function handleMembers(members) {
      if (members) {
        // handleError(error);
        // console.log(members);
        const isOfferer = members.length === 2;
        await startWebRTC(isOfferer);
      }
      // handleSuccess();
    }

    // drone.on('authenticate', handleRoom);
    drone.on('error', handleError);
    drone.on('close', handleClose);
    drone.on('open', handleOpen);
  });
}

This is the error I am getting:


ScaledroneMeet.js:17 DOMException
_callee$ @ ScaledroneMeet.js:17
tryCatch @ runtime.js:65
invoke @ runtime.js:303
prototype.(anonymous function) @ runtime.js:117
asyncGeneratorStep @ bundle.js:4186
_next @ bundle.js:4188
(anonymous) @ bundle.js:4188
(anonymous) @ bundle.js:4188
_handleError @ ScaledroneMeet.js:2
handleError @ ScaledroneMeet.js:2
scaledrone.min.js:288 WebSocket is already in CLOSING or CLOSED state.
(anonymous) @ scaledrone.min.js:288
(anonymous) @ scaledrone.min.js:29
nextTick @ scaledrone.min.js:17
characterData (async)
scheduleDrain @ scaledrone.min.js:17
immediate @ scaledrone.min.js:17
unwrap @ scaledrone.min.js:29
Promise.then @ scaledrone.min.js:29
Scaledrone._sendMessage @ scaledrone.min.js:288
Scaledrone.publish @ scaledrone.min.js:288
sendMessage @ ScaledroneMeet.js:59
pc.onicecandidate @ ScaledroneMeet.js:76
ScaledroneMeet.js:26 Drone disconnected
2scaledrone.min.js:288 WebSocket is already in CLOSING or CLOSED state.
(anonymous) @ scaledrone.min.js:288
(anonymous) @ scaledrone.min.js:29
nextTick @ scaledrone.min.js:17
characterData (async)
scheduleDrain @ scaledrone.min.js:17
immediate @ scaledrone.min.js:17
unwrap @ scaledrone.min.js:29
Promise.then @ scaledrone.min.js:29
Scaledrone._sendMessage @ scaledrone.min.js:288
Scaledrone.publish @ scaledrone.min.js:288
sendMessage @ ScaledroneMeet.js:59
pc.onicecandidate @ ScaledroneMeet.js:76




I imported the code as such:

  <script src='https://cdn.scaledrone.com/scaledrone.min.js'></script> and I can see the source no problem. It's when the second participant connects I get above error. 

I would appreciate any directions! Thanks. 

It's NOT working

Hi,
It seems the script does NOT work for now!?
may I ask to test it and let me know the outcome?
Thanks

remoteVideo not showing

Hi,

I've been testing with the code as provided on my webpage but the remoteVideo is not showing. In my developer console for Chrome, I have this error message: DOMException: Error processing ICE candidate.
I checked out the live demo on https://scaledrone.github.io/webrtc/index.html
The live demo also has the same error message DOMException: Error processing ICE candidate in the console.

When I log onto scaledrone, I can see that there are 2 users in the room, but for both users, the remoteVideo is not showing

Can't retrieve the number of users

Hi!

I would like to ask for some help on retrieving the number of users in the room. I'm using the WebRTC tutorial here

There is a part where we call startWebRTC function based on the number of members in the room.

room.on('members', members => {
   if (members.length >= 3) {
     return alert('The room is full');
   }
   // If we are the second user to connect to the room we will be creating the offer
   const isOfferer = members.length === 2;
   startWebRTC(isOfferer);
   startListentingToSignals();
 });

I might have missunderstood the documentation, I thought this listener will retrieve every member in the room.

When I log out the room and the members variable provided by the listener I get these:
room:

Room {
   name: "observable-REMOVED"
   scaledrone: Scaledrone {args: Arguments(1), originalInstance: Scaledrone, readyState: 2, callbackId: 2, callbacks: {…}, …}
   _cache: [{…}]
   _events: {
      data: [{…}]
      member_join: [{…}]
      members: Array(5)
         0: {callback: ƒ, context: undefined, ctx: Room}
         1: {callback: ƒ, context: undefined, ctx: Room}
         2: {callback: ƒ, context: undefined, ctx: Room}
         3: {callback: ƒ, context: undefined, ctx: Room}
         4: {callback: ƒ, context: undefined, ctx: Room}
...

As you can see here, there is 5 ppl in the room already, while the event listener will log this:
members array in the listener

MEMBERS:
0: {id: "BlrBA6qWpK"}
length: 1
__proto__: Array(0)

Can you please help me out with this one? Is there any other way to retrieve the number of users in the room?

Also forgot to mention that I can see the connected members if I visit my scaledrone dashboard.

Thanks!

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

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.