video calling App in React JS using Simple Peer
Tags: javascript, programming, webdev, beginners
Published: 2022-01-08 04:18:08

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

});

```

## 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;
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3i2d03t3gflxwg5foz4w.png)