DEV Community

Cover image for video calling App in React JS using Simple Peer
Deepak Jaiswal
Deepak Jaiswal

Posted on

31 10 1 1 1

video calling App in React JS using Simple Peer

we talk about web rtc communication to like video
calling web application, audio calling application using simple peer.

npm install simple-peer

simple peer library directly communicate with browser without any extra library or api.

server.js

io.on('connection', function(socket){
  debug('a user connected');

  io.emit('peer', {
    peerId: socket.id
  })

  socket.on('disconnect', reason => {
    io.emit('unpeer', {
      peerId: socket.id,
      reason
    })
  })

  socket.on('signal', msg => {
    debug('signal received', msg)
    const receiverId = msg.to
    const receiver = io.sockets.connected[receiverId]
    if (receiver) {
      const data = {
        from: socket.id,
        ...msg
      }
      debug('sending signal to', receiverId)
      io.to(receiverId).emit('signal', data);
    } else {
      debug('no receiver found', receiverId)
    }
  })

});

Enter fullscreen mode Exit fullscreen mode

client.js

import React, { Component } from 'react';
import Peer from 'simple-peer'
import io from 'socket.io-client'

const debug = require('debug')('screen-share:app')

const ioUrl = 'http://localhost:4000/'
const enableTrickle = true

class App extends Component {

  state = {
    peers: {},
    stream: null
  }

  constructor() {
    super()
    this.onMedia = this.onMedia.bind(this)
    this.createPeer = this.createPeer.bind(this)
    this.getMedia(this.onMedia, err => {
      this.setState({
        mediaErr: 'Could not access webcam'
      })
      debug('getMedia error', err)
    })
  }

  componentDidUpdate() {
    if (this.stream && this.video && !this.video.srcObject) {
      debug('set video stream', this.video, this.stream)
      this.video.srcObject = this.stream
    }
    this.attachPeerVideos()
  }

  attachPeerVideos() {
    Object.entries(this.state.peers).forEach(entry => {
      const [peerId, peer] = entry
      if (peer.video && !peer.video.srcObject && peer.stream) {
        debug('setting peer video stream', peerId, peer.stream)
        peer.video.setAttribute('data-peer-id', peerId)
        peer.video.srcObject = peer.stream
      }
    })
  }

  getMedia(callback, err) {
    const options = { video: true, audio: true }
    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
      return navigator.mediaDevices.getUserMedia(options)
        .then(stream => callback(stream))
        .catch(e => err(e))
    }
    return navigator.getUserMedia(options, callback,  err)
  }

  onMedia(stream) {
    this.stream = stream
    this.forceUpdate() // we have stream
    this.socket = io(ioUrl)
    this.socket.on('peer', msg => {
      const peerId = msg.peerId
      debug('new peer poof!', peerId)
      if (peerId === this.socket.id) {
        return debug('Peer is me :D', peerId)
      }
      this.createPeer(peerId, true, stream)
    })
    this.socket.on('signal', data => {
      const peerId = data.from
      const peer = this.state.peers[peerId]
      if (!peer) {
        this.createPeer(peerId, false, stream)
      }
      debug('Setting signal', peerId, data)
      this.signalPeer(this.state.peers[peerId], data.signal)
    })
    this.socket.on('unpeer', msg => {
      debug('Unpeer', msg)
      this.destroyPeer(msg.peerId)
    })
  }

  createPeer(peerId, initiator, stream) {
    debug('creating new peer', peerId, initiator)

    const peer = new Peer({initiator: initiator, trickle: enableTrickle, stream})

    peer.on('signal', (signal) => {
      const msgId = (new Date().getTime())
      const msg = { msgId, signal, to: peerId }
      debug('peer signal sent', msg)
      this.socket.emit('signal', msg)
    })

    peer.on('stream', (stream) => {
      debug('Got peer stream!!!', peerId, stream)
      peer.stream = stream
      this.setPeerState(peerId, peer)
    })

    peer.on('connect', () => {
      debug('Connected to peer', peerId)
      peer.connected = true
      this.setPeerState(peerId, peer)
      peer.send(this.serialize({
        msg: 'hey man!'
      }))
    })

    peer.on('data', data => {
      debug('Data from peer', peerId, this.unserialize(data))
    })

    peer.on('error', (e) => {
      debug('Peer error %s:', peerId, e);
    })

    this.setPeerState(peerId, peer)

    return peer
  }

  destroyPeer(peerId) {
    const peers = {...this.state.peers}
    delete peers[peerId]
    this.setState({
      peers
    })
  }

  serialize(data) {
    return JSON.stringify(data)
  }

  unserialize(data) {
    try {
      return JSON.parse(data.toString())
    } catch(e) {
      return undefined
    }
  }

  setPeerState(peerId, peer) {
    const peers = {...this.state.peers}
    peers[peerId] = peer
    this.setState({
      peers
    })
  }

  signalPeer(peer, data) {
    try {
      peer.signal(data)
    } catch(e) {
      debug('sigal error', e)
    }
  }

  renderPeers() {
    return Object.entries(this.state.peers).map(entry => {
      const [peerId, peer] = entry
      debug('render peer', peerId, peer, entry)
      return <div key={peerId}>
        <video ref={video => peer.video = video}></video>
      </div>
    })
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">WebRTC Video Chat</h1>
        </header>
        {this.state.mediaErr && (
          <p className="error">{this.state.mediaErr}</p>
        )}
        <div id="me">
          <video id="myVideo" ref={video => this.video = video} controls></video>
        </div>
        <div id="peers">{this.renderPeers()}</div>
      </div>
    );
  }
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Image description

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (2)

Collapse
 
albincsergo profile image
Albin Csergő

How to run this?

Collapse
 
deepakjaiswal profile image
Deepak Jaiswal

It's run on express server and react-script server. Server.js file is part of express and client.js is a component of react app. so it's not a full of code of application but it's whole logic on simple peer and socket.io implementation. Thanks for response.

Cloudinary image

Zoom pan, gen fill, restore, overlay, upscale, crop, resize...

Chain advanced transformations through a set of image and video APIs while optimizing assets by 90%.

Explore

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay