React+PeerJS 实现点对点通话自动接听功能的问题咨询
点对点通话自动接听实现方案
错误根因说明
你之前触发的Cannot read properties of undefined (reading 'renegotiate')报错,是因为逻辑位置放错了:answerCall是被叫侧收到呼叫请求后执行的接听逻辑,你把它放到主叫侧的callUser函数末尾,此时主叫侧根本没有callerSignal、caller这些被叫侧才有的参数,调用peer.signal()时传了空值才会触发报错。
实现自动接听的修改步骤
1. 修改被叫侧呼叫请求监听逻辑
找到useEffect里的socket.on("callUser")监听回调,修改为收到呼叫后,确认媒体流已获取就直接调用answerCall,不需要等待用户点击按钮。
2. 修复原有代码的异步bug
你原来的callUser函数里axios.post请求后直接用randomId拿不到最新值,因为useState的更新是异步的,需要直接用请求返回的结果,避免呼叫请求发空ID。
完整修改后的代码片段
修改后的useEffect部分
useEffect(() => { navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((stream) => { setStream(stream) myVideo.current.srcObject = stream }) socket.on("me", (id) => { setMe(id) axios.post("http://localhost:5000/ex", { displayName: firebase.auth().currentUser.displayName, me: id }) .then(resp => console.log("Me =", resp.data)) }) socket.on("callUser", (data) => { setReceivingCall(true) setCaller(data.from) setName(data.name) setCallerSignal(data.signal) // 新增:确认媒体流已加载后自动接听 if(stream) { answerCall() } }) }, [stream]) // 新增stream作为依赖,确保能拿到最新的流状态
修改后的callUser函数
const callUser = async (id) => { // 修复异步问题,直接用请求返回的id const resp = await axios.post("http://localhost:5000/ex2", { me }) const targetId = resp.data setRandomId(targetId) const peer = new Peer({ initiator: true, trickle: false, stream: stream }) peer.on("signal", (data) => { socket.emit("callUser", { userToCall: targetId, // 直接用请求返回的结果,不用state里的randomId signalData: data, from: me, name: firebase.auth().currentUser.displayName }) }) peer.on("stream", (stream) => { userVideo.current.srcObject = stream }) socket.on("callAccepted", (signal) => { setCallAccepted(true) peer.signal(signal) }) connectionRef.current = peer }
注意事项
- 如果你需要保留手动接听的入口,只需要给自动接听的逻辑加开关控制即可,不需要删除原有Answer按钮。
- 部分浏览器会要求音视频通话必须有用户交互触发,如果你碰到自动接听时媒体流加载失败,可以提前在页面加载后加一个简单的用户交互引导(比如进入页面前点击"进入"按钮),获取交互权限后就可以正常自动接听。
内容的提问来源于stack exchange,提问作者KylianMbappe
相关产品推荐
相关产品推荐

