Remote stream is showing blank, unable to figure out why, please help

I’m using expo 49 and react-native v0.72.3,

I seem to be getting video stream but it shows blank in RCTView however Local stream does show properly, Any help is much appreciated, I’m stuck

Here’s code :

import React, { useState, useEffect } from 'react';
import { View, Text, Button } from 'react-native';
import { RTCPeerConnection, RTCView, mediaDevices } from 'react-native-webrtc';
import socket from './socket';
import { SafeAreaView } from 'react-native-safe-area-context';

const STUN_SERVERS = [
];
const VideoCall = () => {
  const [localStream, setLocalStream] = useState(null);
  const [remoteStream, setRemoteStream] = useState(null);
  const [peerConnections, setPeerConnections] = useState([]);
  const socketInstance =  socket()

  useEffect(() => {
    // Initialize local stream
    mediaDevices.getUserMedia({ audio: true, video: true })
      .then(stream => setLocalStream(stream))
      .catch(error => console.error('Error getting user media:', error));

    return () => {
      socketInstance.disconnect(); // Clean up socketInstance connection on component unmount
    };
  }, []);
  
  useEffect(() => {
    if (localStream) {
      // Create a peer connection for each user
      const pc = new RTCPeerConnection({
        iceServers: STUN_SERVERS,
        sdpSemantics: 'unified-plan',
      });
      setPeerConnections(prevConnections => [...prevConnections, pc]);
  
      // Add local stream to peer connection
      localStream.getTracks().forEach(track => pc.addTrack(track, localStream));
  
      // Handle ICE candidate events
      pc.onicecandidate = event => {
        if (event.candidate) {
          // Send ICE candidate to all connected clients
          socketInstance.emit('ice-candidate', { candidate: event.candidate });
        }
      };
  
      // Handle remote stream events
      pc.ontrack = event => {
        setRemoteStream(event.streams[0]);
      };
      pc.onupdatetrack = event => {
        // Update remoteStream if the video track changes
        setRemoteStream(event.streams[0]);
      };
    }
  }, [localStream]);
  
  useEffect(()=>{
    if (localStream){
      socketInstance.on('offer', data => {
        handleOffer(data);
      });
    }
  }, [localStream])

  const handleOffer = data => {
    if (!localStream) {
      console.error('Local stream is not yet available');
      return;
    }
  
    const pc = new RTCPeerConnection({
      iceServers: STUN_SERVERS,
      sdpSemantics: 'unified-plan',
    });
    setPeerConnections(prevConnections => [...prevConnections, pc]);
  
    pc.onicecandidate = event => {
      if (event.candidate) {
        socketInstance.emit('ice-candidate', { candidate: event.candidate });
      }
    };
  
    pc.ontrack = event => {
      const receivedOffer = data.offer.sdp;
      if (receivedOffer.includes("audio") && receivedOffer.includes("video")) {
        console.log("Received offer contains both audio and video.");
      } else {
        console.error("Received offer does not contain expected media types.");
      }
      console.log("Received tracks:", event.streams[0].getTracks()); // Log the tracks
      // Check the kind of the track
      if (event.track.kind === 'video') {
        // Set remoteStream to the received video track
        setRemoteStream(event.streams[0]);
      }
    };
  
    pc.onupdatetrack = event => {
      // Update remoteStream if the video track changes
      setRemoteStream(event.streams[0]);
    };
  
    pc.setRemoteDescription(data.offer)
      .then(() => pc.createAnswer())
      .then(answer => {
        console.log("Received offer:", data.offer.sdp); // Log the received offer
        console.log("Created answer:", answer.sdp);
        socketInstance.emit('answer', {
          answer,
          senderSocketId: data.senderUserId
        });
        return pc.setLocalDescription(answer);
      });
  };
  

  useEffect(() => {
    console.log('remote stream inUseeffect: ', remoteStream);
  }, [remoteStream]);
       
  const handleCall = () => {
    // Send offer to all connected clients
    peerConnections.forEach(pc => {
      pc.createOffer()
        .then(offer => {
          // Send the offer to all clients
          socketInstance.emit('offer', {
            offer
          });
          pc.setLocalDescription(offer);
        });
    });
  };  
  
  return (
    <SafeAreaView>
      <Text>Video Call Screen</Text>
      {remoteStream && <RTCView streamURL={remoteStream.toURL()} zOrder={20} style={{ width: 200, height: 150 }} />}
      {localStream && <RTCView streamURL={localStream.toURL()} zOrder={-1} style={{ width: 200, height: 150 }} />}
      <Button title="Call" onPress={handleCall} />
    </SafeAreaView>
  );
};

export default VideoCall;

Here are my console logs:

LOG  Received offer: v=0 o=- 589488281341570380 2 IN IP4 127.0.0.1 s=- t=0 0 a=group:BUNDLE 0 1 a=extmap-allow-mixed a=msid-semantic: WMS 4fdccd0d-4728-4c11-9c68-0e7c512277c8 m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 102 0 8 13 110 126 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:ycdf a=ice-pwd:mMpVj3hpcTCUmEcmWnP2PC9c a=ice-options:trickle renomination a=fingerprint:sha-256 8F:E0:82:B4:B4:C3:8A:89:86:4C:14:3A:80:D5:7E:4B:3D:9C:02:79:32:EC:8D:54:A1:25:AF:9E:67:6B:81:41 a=setup:actpass a=mid:0 a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid a=sendrecv a=msid:4fdccd0d-4728-4c11-9c68-0e7c512277c8 49fdcbf9-aee6-4701-b070-97ff89e5113c a=rtcp-mux a=rtpmap:111 opus/48000/2 a=rtcp-fb:111 transport-cc a=fmtp:111 minptime=10;useinbandfec=1 a=rtpmap:63 red/48000/2 a=fmtp:63 111/111 a=rtpmap:9 G722/8000 a=rtpmap:102 ILBC/8000 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:13 CN/8000 a=rtpmap:110 telephone-event/48000 a=rtpmap:126 telephone-event/8000 a=ssrc:329664454 cname:HfRuU/4fxOIos/jP a=ssrc:329664454 msid:4fdccd0d-4728-4c11-9c68-0e7c512277c8 49fdcbf9-aee6-4701-b070-97ff89e5113c m=video 9 UDP/TLS/RTP/SAVPF 98 99 39 40 100 101 127 103 104 105 106 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:ycdf a=ice-pwd:mMpVj3hpcTCUmEcmWnP2PC9c a=ice-options:trickle renomination a=fingerprint:sha-256 8F:E0:82:B4:B4:C3:8A:89:86:4C:14:3A:80:D5:7E:4B:3D:9C:02:79:32:EC:8D:54:A1:25:AF:9E:67:6B:81:41 a=setup:actpass a=mid:1 a=extmap:14 urn:ietf:params:rtp-hdrext:toffset a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:13 urn:3gpp:video-orientation a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id a=sendrecv a=msid:4fdccd0d-4728-4c11-9c68-0e7c512277c8 a4cbe637-2133-4354-a846-9c48b3eb178f a=rtcp-mux a=rtcp-rsize a=rtpmap:98 VP8/90000 a=rtcp-fb:98 goog-remb a=rtcp-fb:98 transport-cc a=rtcp-fb:98 ccm fir a=rtcp-fb:98 nack a=rtcp-fb:98 nack pli a=rtpmap:99 rtx/90000 a=fmtp:99 apt=98 a=rtpmap:39 AV1/90000 a=rtcp-fb:39 goog-remb a=rtcp-fb:39 transport-cc a=rtcp-fb:39 ccm fir a=rtcp-fb:39 nack a=rtcp-fb:39 nack pli a=rtpmap:40 rtx/90000 a=fmtp:40 apt=39 a=rtpmap:100 VP9/90000 a=rtcp-fb:100 goog-remb a=rtcp-fb:100 transport-cc a=rtcp-fb:100 ccm fir a=rtcp-fb:100 nack a=rtcp-fb:100 nack pli a=fmtp:100 profile-id=0 a=rtpmap:101 rtx/90000 a=fmtp:101 apt=100 a=rtpmap:127 VP9/90000 a=rtcp-fb:127 goog-remb a=rtcp-fb:127 transport-cc a=rtcp-fb:127 ccm fir a=rtcp-fb:127 nack a=rtcp-fb:127 nack pli a=fmtp:127 profile-id=2 a=rtpmap:103 rtx/90000 a=fmtp:103 apt=127 a=rtpmap:104 red/90000 a=rtpmap:105 rtx/90000 a=fmtp:105 apt=104 a=rtpmap:106 ulpfec/90000 a=ssrc-group:FID 4186340422 1365907217 a=ssrc:4186340422 cname:HfRuU/4fxOIos/jP a=ssrc:4186340422 msid:4fdccd0d-4728-4c11-9c68-0e7c512277c8 a4cbe637-2133-4354-a846-9c48b3eb178f a=ssrc:1365907217 cname:HfRuU/4fxOIos/jP a=ssrc:1365907217 msid:4fdccd0d-4728-4c11-9c68-0e7c512277c8 a4cbe637-2133-4354-a846-9c48b3eb178f 

LOG  Created answer: v=0 o=- 7187305411903491617 2 IN IP4 127.0.0.1 s=- t=0 0 a=group:BUNDLE 0 1 a=extmap-allow-mixed a=msid-semantic: WMS m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 102 0 8 13 110 126 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:RjHl a=ice-pwd:nTACNClBNTkuMH3dcCqZdyQI a=ice-options:trickle renomination a=fingerprint:sha-256 A6:51:11:A2:60:09:A5:B7:7F:A4:40:5C:E0:6A:E9:68:79:83:0A:17:D7:75:CB:1E:BA:B0:02:9D:07:62:81:BA a=setup:active a=mid:0 a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid a=recvonly a=rtcp-mux a=rtpmap:111 opus/48000/2 a=rtcp-fb:111 transport-cc a=fmtp:111 minptime=10;useinbandfec=1 a=rtpmap:63 red/48000/2 a=fmtp:63 111/111 a=rtpmap:9 G722/8000 a=rtpmap:102 ILBC/8000 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:13 CN/8000 a=rtpmap:110 telephone-event/48000 a=rtpmap:126 telephone-event/8000 m=video 9 UDP/TLS/RTP/SAVPF 98 99 39 40 100 101 127 103 104 105 106 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:RjHl a=ice-pwd:nTACNClBNTkuMH3dcCqZdyQI a=ice-options:trickle renomination a=fingerprint:sha-256 A6:51:11:A2:60:09:A5:B7:7F:A4:40:5C:E0:6A:E9:68:79:83:0A:17:D7:75:CB:1E:BA:B0:02:9D:07:62:81:BA a=setup:active a=mid:1 a=extmap:14 urn:ietf:params:rtp-hdrext:toffset a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:13 urn:3gpp:video-orientation a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id a=recvonly a=rtcp-mux a=rtcp-rsize a=rtpmap:98 VP8/90000 a=rtcp-fb:98 goog-remb a=rtcp-fb:98 transport-cc a=rtcp-fb:98 ccm fir a=rtcp-fb:98 nack a=rtcp-fb:98 nack pli a=rtpmap:99 rtx/90000 a=fmtp:99 apt=98 a=rtpmap:39 AV1/90000 a=rtcp-fb:39 goog-remb a=rtcp-fb:39 transport-cc a=rtcp-fb:39 ccm fir a=rtcp-fb:39 nack a=rtcp-fb:39 nack pli a=rtpmap:40 rtx/90000 a=fmtp:40 apt=39 a=rtpmap:100 VP9/90000 a=rtcp-fb:100 goog-remb a=rtcp-fb:100 transport-cc a=rtcp-fb:100 ccm fir a=rtcp-fb:100 nack a=rtcp-fb:100 nack pli a=fmtp:100 profile-id=0 a=rtpmap:101 rtx/90000 a=fmtp:101 apt=100 a=rtpmap:127 VP9/90000 a=rtcp-fb:127 goog-remb a=rtcp-fb:127 transport-cc a=rtcp-fb:127 ccm fir a=rtcp-fb:127 nack a=rtcp-fb:127 nack pli a=fmtp:127 profile-id=2 a=rtpmap:103 rtx/90000 a=fmtp:103 apt=127 a=rtpmap:104 red/90000 a=rtpmap:105 rtx/90000 a=fmtp:105 apt=104 a=rtpmap:106 ulpfec/90000
 LOG  Received offer contains both audio and video.

I haven’t tested it on IOS But it doesn’t work on android

Is there anyone who can help?

Generally speaking the code looks functional, could be optimised plenty though ofcourse.
You also don’t need to specify sdpSemantics: 'unified-plan' as that is the only supported SDP format and has been for a while, plan-b was removed.

Can you provide more logs?
Are there any errors?