import {
mediaDevices,
RTCPeerConnection,
RTCView,
RTCIceCandidate,
RTCSessionDescription,
MediaStream,
} from 'react-native-webrtc';
import styles from './callPageStyle';
import { useEffect, useState, useRef } from "react";
const CallPage = ({ route, navigation }) => {
// const navigation = useNavigation();
const userData = useSelector((state) => state.userData);
const dispatch = useDispatch();
const { callerId, calleeId, calleeName, isVideo, isCreator } = route.params;
const [localStream, setLocalStream] = useState(null);
const [remoteStream, setRemoteStream] = useState(null);
const [callStarted, setCallStarted] = useState(false);
const peerConnectionRef = useRef(null);
const remoteRTCMessage = useRef(null);
useEffect(() => {
const recipientID = isCreator ? calleeId : callerId;
webSocketService.registerSendCallMessageCallback(recipientID, onNewCall);
webSocketService.registerAnswerCallMessageCallback(recipientID, onCallAnswered);
webSocketService.registerICECandidateMessageCallback(recipientID, onICEcandidate);
const initLocalStream = async () => {
const stream = await mediaDevices.getUserMedia({ audio: true, video: true });
setLocalStream(stream);
};
const delayProcessCall = setTimeout(() => {
if (!isCreator) {
startCall();
} else {
initLocalStream();
}
}, 2000);
return () => {
clearTimeout(delayProcessCall);
if (localStream) {
localStream.getTracks().forEach((track) => track.stop());
}
};
}, []);
const createPeerConnection = async () => {
const configuration = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun1.l.google.com:19302' },
{ urls: 'stun:stun2.l.google.com:19302' },
],
};
const peerConnection = new RTCPeerConnection(configuration);
// Use a promise to wait for getUserMedia to complete
const stream = await mediaDevices.getUserMedia({ audio: true, video: true });
stream.getTracks().forEach((track) => peerConnection.addTrack(track, stream));
setLocalStream(stream);
return new Promise((resolve) => {
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
webSocketService.sendICECandidateToPeerServer(userData.id, isCreator ? calleeId : callerId, {
calleeId: isCreator ? calleeId : callerId,
rtcMessage: {
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate,
},
});
} else {
console.log("End of candidates.");
}
};
peerConnection.ontrack = (event) => {
setRemoteStream(event.streams[0]);
};
peerConnectionRef.current = peerConnection;
resolve();
});
};
const startCall = async () => {
try {
console.log("=========sendNewCallToPeerServer===========");
await createPeerConnection();
const offer = await peerConnectionRef.current.createOffer();
await peerConnectionRef.current.setLocalDescription(offer);
webSocketService.sendNewCallToPeerServer(userData.id, isCreator ? calleeId : callerId, {
calleeId: isCreator ? calleeId : callerId,
rtcMessage: offer,
});
console.log("=========sendNewCallToPeerServer===========");
} catch (error) {
console.error('Error creating offer:', error);
}
};
const handleAnswer = async () => {
try {
const answer = await peerConnectionRef.current.createAnswer();
await peerConnectionRef.current.setLocalDescription(answer);
webSocketService.sendAnswerCallToPeerServer(userData.id, isCreator ? calleeId : callerId, {
calleeId: isCreator ? calleeId : callerId,
rtcMessage: answer,
});
setCallStarted(true);
} catch (error) {
console.error('Error creating answer:', error);
}
};
const onNewCall = async (payload) => {
console.log("On New Call !!!");
const bigData = JSON.parse(payload.body);
const data = JSON.parse(bigData.data);
remoteRTCMessage.current = data.rtcMessage;
await createPeerConnection();
peerConnectionRef.current.setRemoteDescription(
new RTCSessionDescription(remoteRTCMessage.current)
);
handleAnswer();
};
const onCallAnswered = (payload) => {
console.log("onCallAnswered !!!");
const bigData = JSON.parse(payload.body);
const data = JSON.parse(bigData.data);
remoteRTCMessage.current = data.rtcMessage;
peerConnectionRef.current.setRemoteDescription(
new RTCSessionDescription(remoteRTCMessage.current)
);
setCallStarted(true);
};
const onICEcandidate = (payload) => {
console.log("onICEcandidate !!!");
const bigData = JSON.parse(payload.body);
const data = JSON.parse(bigData.data);
let message = data.rtcMessage;
if (peerConnectionRef.current) {
peerConnectionRef.current
.addIceCandidate(new RTCIceCandidate({candidate: message.candidate, sdpMLineIndex: message.label, sdpMid: message.id}))
.then((data) => {
console.log("SUCCESS");
})
.catch((err) => {
console.log("Error", err);
});
}
};
这是我在react-native expo应用程序中实现视频通话功能的源代码。
我目前正在使用下面的react-native-webrtc库。
@config-plugins/react-native-webrtc": "^7.0.0
react-native-webrtc": "^111.0.3
,
我正在使用这样的Android模拟器:
在对等点之间建立连接的所有逻辑都运行良好。但视频流有问题。 帮助我纠正源代码或提供任何建议。 谢谢。
我以前也遇到过这样的问题。 使用WebRTC流实现视频通话包含这样一个复杂的过程。 有更简单的方法来实现视频通话,而无需使用基本库。 我建议在 React Native 中使用“agora-rn-uikit”库。
更多详细说明在这里:
https://www.npmjs.com/package/agora-rn-uikit
安装命令:
npm i react-native-agora agora-react-native-rtm agora-rn-uikit
示例代码:
const connectionData = {
appId: '<Agora App ID>',
channel: 'test',
};
const rtcCallbacks = {
EndCall: () => setVideoCall(false),
};
<AgoraUIKit connectionData={connectionData} rtcCallbacks={rtcCallbacks} />
使用方便,开发速度更快。