Usman
Usman

Reputation: 87

WebRTC with ReactJS and Socket.io doesn't show Remote Stream

I am trying to make a Zoom-like video call app with ReactJS and Socket.io using WebRTC.I am using NodeJS(socket.io) as the signaling server. I have gone through the process of creating an offer and making the answer.The connection is in stable state. I get the media stream from the remote peer and add it to the video element but for some reason the video doesn't show up in the element. Only the grey screen. Following is my code

ReactJS code

import React, { useState, useEffect, useRef } from 'react'
import { socket } from '../socket';

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

export function VideoPlayer () {
  const localVideoRef = useRef(null)
  const videoRef = useRef(null)
  const [users, setUsers] = useState([])

  async function setStream(peerConnection) {
    const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
    localVideoRef.current.srcObject = stream
    PC.addStream(stream);
  }

  const onAddStream = obj => {
    let vid = document.createElement('video');
    vid.setAttribute('class', 'video-small');
    vid.setAttribute('autoplay', 'autoplay');
    vid.setAttribute('muted', 'muted');
    vid.setAttribute('crossorigin', 'anonymous')
    vid.setAttribute('id', 'video-small');

    document.getElementById('users-container').appendChild(vid)
    vid.src = obj.stream
  }

  const handleAddUsers = data => {
    setUsers(data.users)
  }

  const createOffer = async id => {
    const offer = await PC.createOffer()

    await PC.setLocalDescription(offer)

    socket.emit('make-offer', {
      offer: offer,
      to: id
    })
  }

  const handleOffer = data => {
    const offer = data.offer

    PC.setRemoteDescription(new RTCSessionDescription(offer), async () => {
      
      const answer = await PC.createAnswer()
      await PC.setLocalDescription(answer)

      socket.emit('make-answer', {
        answer: answer,
        to: data.socket
      })
    })
  }

  const handleAnswer = data => {
    const answer = data.answer
    
    PC.setRemoteDescription(new RTCSessionDescription(answer), async () => {
      document.getElementById(data.socket).setAttribute('class', 'active');
    })
  }

  useEffect(() => {
    PC.onaddstream = onAddStream
    setStream(PC)

    socket.on('add-users', handleAddUsers)
    socket.on('offer-made', handleOffer)
    socket.on('answer-made', handleAnswer)
    window.addEventListener("iceconnectionstatechange", (event) => {
      console.log(event)
    });

    return () => {
      PC.onaddstream = null
      socket.off('add-users', handleAddUsers)
      socket.off('offer-made', handleOffer)
      socket.off('answer-made', handleAnswer)
    }

  }, [])

  return(
    <div className='container'>
      <video style={{ width: '100%', height: 'auto' }} id='localVideo' ref={localVideoRef} autoPlay muted />
      <div className='users-container' id='users-container'>
        <h4>Users</h4>
        <div id='users'>
          {users.map(id => (
            <div id={id} onClick={() => createOffer(id)}>{id}</div>
          ))}
        </div>
      </div>
    </div>
  )
} 

The styles applied to the above code are as follows

html, body {
padding: 0px;
margin: 0px;
}

video {
background: #CCC;
}

.container {
width: 100%;
}

.video-large {
width: 75%;
float: left;
}

.users-container {
width: 21%;
float: left;
padding: 2%;
position: relative;
}

.video-small {
margin-top: 20px;
width: 100%;
}

#users div {
color: red;
text-decoration: underline;
cursor: pointer;
}

#users .active {
color: #000;
cursor: default;
}

And finally the relevant NodeJS code (signaling server)

const app = express()
const server = require('http').createServer(app);
const io = require('socket.io')(server, {
  cors: {
    origin: "http://localhost:3000"
  }
})

const clients = [];

io.on('connection', socket => {
  socket.emit('add-users', {
    users: clients
  })

  socket.broadcast.emit('add-users', {
    users: [socket.id]
  })

  socket.on('make-offer', function (data) {
    socket.to(data.to).emit('offer-made', {
      offer: data.offer,
      socket: socket.id
    });
  });

  socket.on('make-answer', function (data) {
    socket.to(data.to).emit('answer-made', {
      socket: socket.id,
      answer: data.answer
    });
  });

  socket.on('disconnect', function () {
    clients.splice(clients.indexOf(socket.id), 1);
    io.emit('remove-user', socket.id);
  });


  clients.push(socket.id)
})

What i am thinking is the issue might be with iceconnectionstate, as i have added an event listener on iceconnectionstatechange and it never moves on from new state. But i am not sure how to resolve that or even if that is an issue

Upvotes: 0

Views: 381

Answers (0)

Related Questions