Error setting remote description and creating answer in WebRTC application

60 Views Asked by At

I'm developing a WebRTC application, and I'm encountering an error related to setting the remote description and creating an answer. I'm using the WebRTC API, and when I attempt to set the remote description for the answer, I'm getting the following error:``

Expected Behavior: I expected to set the local stream and remote stream on the client screen, but currently only the local stream is displayed.

import React, { useCallback, useEffect, useState } from "react";
import { useSocket } from "../providers/Socket";
import { usePeer } from "../providers/Peer";

const RoomPage = () => {
  const { socket } = useSocket();
  const { peer } = usePeer();
  const {
    createOffer,
    createAnswer,
    setRemoteAns,
    sendStream,
    remoteStream,
    setRemoteStream,
  } = usePeer();
  const [myStream, setMyStream] = useState(null);
  const [remoteEmailId, setRemoteEmailId] = useState(null);

  const handleNewUserJoined = useCallback(
    async (data) => {
      const { emailId } = data;
      console.log("New user joined room : ", emailId);
      const offer = await createOffer();
      socket.emit("call-user", { emailId, offer });
      setRemoteEmailId(emailId);
    },
    [createOffer, socket]
  );

  const handleIncomingCall = useCallback(
    async (data) => {
      const { from, offer } = data;
      console.log("Incoming call from ", from, offer);

      const ans = await createAnswer(offer);
      socket.emit("call-accepted", { emailId: from, ans });
      setRemoteEmailId(from);
    },
    [createAnswer, socket]
  );

  const handleCallAccepted = useCallback(
    async (data) => {
      const { ans } = data;
      console.log("Call got accepted: ", ans);

      if (peer) {
        try {
          await setRemoteAns(ans); // Set the remote answer
        } catch (error) {
          console.error("Error setting remote description (answer):", error);
        }
      }
    },
    [peer, setRemoteAns]
  );

  const getUserMediaStream = useCallback(async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true,
      });

      setMyStream(stream);
      setRemoteStream(remoteStream);
    } catch (error) {
      console.error("Error accessing user media:", error);
    }
  }, []);

  const handleNegotiation = useCallback(async () => {
    const localOffer = peer.localDescription;
    socket.emit("call-user", { emailId: remoteEmailId, offer: localOffer });
  }, [peer.localDescription, remoteEmailId, socket]);

  useEffect(() => {
    socket.on("user-joined", handleNewUserJoined);
    socket.on("incoming-call", handleIncomingCall);
    socket.on("call-accepted", handleCallAccepted);

    return () => {
      socket.off("user-joined", handleNewUserJoined);
      socket.off("incoming-call", handleIncomingCall);
      socket.off("call-accepted", handleCallAccepted);
    };
  }, []);

  useEffect(() => {
    peer.addEventListener("negotiationneeded", handleNegotiation);
    return () => {
      peer.removeEventListener("negotiationneeded", handleNegotiation);
    };
  }, [handleNegotiation]);
  useEffect(() => {
    getUserMediaStream();
  }, [getUserMediaStream]);

  const handleSendVideo = () => {
    console.log("Sending video stream...");
    sendStream(myStream);
  };
  return (
    <div className="room-page-container">
      <h1>Room Page</h1>
      <h4>You are connected to {remoteEmailId}</h4>
      <button onClick={handleSendVideo}>Send my Video</button>
      {myStream && (
        <video
          autoPlay
          playsInline
          muted
          ref={(videoRef) => {
            if (videoRef) {
              videoRef.srcObject = myStream;
            }
          }}
        ></video>
      )}
      {remoteStream && (
        <video
          autoPlay
          playsInline
          ref={(videoRef) => {
            if (videoRef) {
              videoRef.srcObject = remoteStream;
            }
          }}
        ></video>
      )}
    </div>
  );
};

export default RoomPage;
import React, { useMemo, useState, useCallback, useEffect } from "react";

const PeerContext = React.createContext(null);

export const usePeer = () => React.useContext(PeerContext);

export const PeerProvider = (props) => {
  const [peer, setPeer] = useState(null);
  const [remoteStream, setRemoteStream] = useState(null);

  useEffect(() => {
    const initPeer = async () => {
      const rtcPeer = new RTCPeerConnection({
        iceServers: [
          {
            urls: [
              "stun:stun.l.google.com:19302",
              "stun:global.stun.twilio.com:3478",
            ],
          },
        ],
      });

      setPeer(rtcPeer);
    };

    initPeer();
  }, []);

  const handleTrackEvent = useCallback((ev) => {
    const streams = ev.streams;
    setRemoteStream(streams[0]);
  }, []);

  useEffect(() => {
    if (peer) {
      peer.addEventListener("track", handleTrackEvent);

      return () => {
        peer.removeEventListener("track", handleTrackEvent);
      };
    }
  }, [handleTrackEvent, peer]);

  const createOffer = useCallback(async () => {
    if (peer) {
      const offer = await peer.createOffer();
      await peer.setLocalDescription(offer);
      return offer;
    }
    return null;
  }, [peer]);

  const createAnswer = async (offer) => {
    if (peer) {
      try {
        await peer.setRemoteDescription(offer); // Set the remote offer
        const answer = await peer.createAnswer();
        await peer.setLocalDescription(answer); // Set the local answer
        return answer;
      } catch (error) {
        console.error("Error creating answer:", error);
        return null;
      }
    }
    return null;
  };

  const setRemoteAns = async (ans) => {
    if (peer) {
      try {
        await peer.setRemoteDescription(ans); // Set the remote answer
      } catch (error) {
        console.error("Error setting remote description (answer):", error);
      }
    }
  };

  const sendStream = async (stream) => {
    if (peer) {
      const tracks = stream.getTracks();
      tracks.forEach((track) => {
        if (!peer.getSenders().some((sender) => sender.track === track)) {
          peer.addTrack(track, stream);
        }
      });
    }
  };

  return (
    <PeerContext.Provider
      value={{
        peer,
        createOffer,
        createAnswer,
        setRemoteAns,
        sendStream,
        remoteStream,
        setRemoteStream,
      }}
    >
      {props.children}
    </PeerContext.Provider>
  );
};

Additional Information:

My application runs on a localhost server (http://localhost:3000). I'm using the Socket.IO library for real-time communication. I'm using the WebRTC API for establishing peer connections.

Question:

What is causing these errors related to setting the remote description and creating an answer in my WebRTC application? How can I resolve these errors and successfully set the remote description and create an answer? Any insights or suggestions on how to address these issues would be greatly appreciated. Thank you!

0

There are 0 best solutions below