无法在'RTCPeerConnection'上执行'addIceCandidate':在React.js中处理ICE候选者时出错

问题描述

在进行视频聊天时,我遇到了addIceCandidate的错误。有时它工作正常,有时则不行。我发现直接进入视频路线时,视频聊天功能正常。但是,如果我以编程方式进行操作,则无法正常工作,则显示错误

以编程方式表示,在我的应用程序中,对于视频聊天,应该将请求发送给另一位用户。并且在接受两个用户都可以重定向到视频路由之后。我使用Firebase对其进行了管理。当两个用户都在视频路线上并且其中一个发送了创建要约请求时,在另一端(即在另一用户端显示

无法在“ RTCPeerConnection”上执行“ addIceCandidate”:处理ICE候选者时出错

这是我的videoChat组件videoChat.js

  const localVideoRef = useRef();
  const remoteVideoRef = useRef();
const pc_config = {
    iceServers: [
      {
        urls: "stun:stun.l.google.com:19302",},],};
  let pc = new RTCPeerConnection(pc_config);
 let recordedChunks = [];

  useEffect(() => {
    if (
      localStorage.getItem("id") &&
      localStorage.getItem("debateAccountToken") &&
      localStorage.getItem("email")
    ) {
      socket.current = io.connect("http://localhost:8000/webrtcPeer"); 

      socket.current.on("connection-success",(success) => {
        console.log("connection... ",success);
      });

      // when createOffer() called this event is fired
      socket.current.on("offerOrAnswer",async (sdp) => {
        console.log("offerOrAnswer event called",sdp);
        let sessionDesc = await new RTCSessionDescription(sdp);
        pc.setRemoteDescription(sessionDesc)
          .then((result) => {
            console.log("result...",result);
          })
          .catch((err) => {
            console.log("errr.. ",err);
          });
      });

      // createOffer() is also calling candidate event
      socket.current.on("candidate",async (candidate) => {
        console.log("candidate.. ");
        const newCandidate = await new RTCIceCandidate(candidate);
        if (candidate) await pc.addIceCandidate(newCandidate);
      });

      pc.onicecandidate = (e) => {
        console.log("on ice candidate.. ",e);
        if (!e || !e.candidate) return;
        if (e.candidate) {
          sendToPeer("candidate",e.candidate);
        }
      };

      pc.oniceconnectionstatechange = (e) => {
        console.log("e... ",e);

        if (
          e.target.connectionState == "connected" ||
          e.target.connectionState == "connecting"
        ) {
          const options = { mimeType: "video/webm; codecs=vp9" };
          recordScreen()
            .then((captureStream) => {
              mediaRecorder = new MediaRecorder(captureStream,options);

              mediaRecorder.ondataavailable = handleDataAvailable;
              mediaRecorder.start();
              setTimeout((event) => {
                console.log("stopping",mediaRecorder.state);
                mediaRecorder.stop();
                captureStream.getTracks().forEach((track) => track.stop());
                captureStream.oninactive = (ev) => {
                  console.log("on remove track ",ev);
                  socket.current.emit("disconnect");
                  socket.current.disconnect();
                  console.log("socket disconnected",mediaRecorder.state);
                  pc.close();
                };
              },30000);
            })
            .catch((err) => console.log("error in record screen ",err));
        }
      };

      // createOffer() will call ontrack event
      pc.ontrack = (e) => {
        remoteVideoRef.current.srcObject = e.streams[0];
      };

      pc.onnegotiationneeded = async () => {
        const offer = await pc.createOffer();
        console.log("offer created.. ",offer);
        if (pc.signalingState != "stable") return;
        await pc.setLocalDescription(offer);
      };

      navigator.mediaDevices
        .getUserMedia({ video: true,audio: true })
        .then((stream) => {
          window.localStream = stream;
          localVideoRef.current.srcObject = stream;

          stream.getTracks().forEach((track) => pc.addTrack(track,stream));
        })
        .catch((error) => {
          console.log("errror.. ",error.toString());
          toast.error(error);
        });

     } else {
      history.push("/");
    }
  },[]);

  const sendToPeer = (messageType,payload) => {
    console.log("send to peer fn called...",messageType,payload);
    socket.current.emit(messageType,{
      socketID: socket.current.id,payload,});
  };

  const handleDataAvailable = async (event) => {
    console.log("data-available",event);
    if (event.data.size > 0) {
      recordedChunks.push(event.data);
      download();
    } else {
      // ...
      console.log("in else");
    }
  };

  const download = async () => {
    console.log("in download fn");
    var blob = await new Blob(recordedChunks,{
      type: "video/mp4",});

    var url = URL.createObjectURL(blob);

// api call
  };

const createOffer = () => {
    console.log("offer created ");

    pc.createOffer({ offerToReceiveAudio: 1,offerToReceiveVideo: 1 }).then(
      (sdp) => {
        console.log("sdp... ",sdp);
        pc.setLocalDescription(sdp);

        sendToPeer("offerOrAnswer",sdp);
      }
    );
  };

  const createAnswer = () => {
    console.log("answer.. ");

    pc.createAnswer({ offerToReceiveVideo: 1,offerToReceiveAudio: 1 })
      .then((sdp) => {
        pc.setLocalDescription(sdp);

        sendToPeer("offerOrAnswer",sdp);
        setCallAccepted(true);
      })
      .catch((error) => {
        console.log("error in create answer",error);
      });
  };

  async function recordScreen() {
    console.log("recordScreen fn called");
    let captureStream = null;

    return navigator.mediaDevices
      .getdisplayMedia({
        video: true,audio: true,})
      .catch((err) => {
        console.error("Error:" + err);
        return null;
      });
  }

return (
<div className="row" style={{ marginLeft: "5px" }}>
          <div className="col-6">
            <video
              style={{ width: "65%",height: "65%" }}
              controls
              ref={localVideoRef}
              autoplay
            ></video>
          </div>
          <div className="col-6">
            <video
              style={{ width: "65%",height: "65%" }}
              controls
              ref={remoteVideoRef}
              autoplay
            ></video>
          </div>
        </div>
<button onClick={createOffer}>Offer</button>
        <button onClick={createAnswer}>Answer</button>
)

这是我在节点js中的后端主文件

const express = require("express");
const http = require("http");
const app = express();
const server = http.createServer(app);
const socket = require("socket.io");
const io = socket(server);
const peers = io.of("/webrtcPeer");

let connectedPeers = new Map();

peers.on("connection",(socket) => {
  console.log("connection established.. ",socket.id);

  socket.emit("connection-success",{ success: socket.id });

  connectedPeers.set(socket.id,socket);

  socket.on("disconnect",() => {
    console.log("disconnected");
    connectedPeers.delete(socket.id);
  });

  socket.on("offerOrAnswer",(data) => {
    for (const [socketID,socket] of connectedPeers.entries()) {
      if (socketID !== data.socketID) {
        console.log("offerOrAnswer ",socketID,data.payload.type);
        socket.emit("offerOrAnswer",data.payload);
      }
    }
  });

  socket.on("candidate",(data) => {
    // send candidate to the other peer(s) if any
    for (const [socketID,socket] of connectedPeers.entries()) {
      // don't send to self
      if (socketID !== data.socketID) {
        console.log("on candidate event ",data);
        socket.emit("candidate",data.payload);
      }
    }
  });
});

此addIceCandidate错误不会再出现,最初是显示错误无法创建答案。也许我在某个地方弄错了。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)