我正在开发一个具有视频通话功能的 React Native 应用程序,我在实现中遇到了一个问题,我收到了这个错误 ERROR Failed to add ice candidate: [Error: The remote description was null] 虽然电话还没有开始。 这段代码是用webrtc调用特定的人,这是我的代码,希望看到这篇的人能帮助我实现,我还是个初学者。 错误从 collectIceCandidates 的最后一行之后开始,它总是会捕获错误,就像我之前说的一样。
import React, {useState, useRef, useEffect} from 'react';
import {Text, StyleSheet, Button, View, TouchableOpacity} from 'react-native';
import GettingCall from './GettingCall';
import Video from './Video';
import Colors from '../../../Styles/Colors';
import AsyncStorage from '@react-native-async-storage/async-storage';
//import Sound from 'react-native-sound';
import {useSurfaceScale} from '@react-native-material/core/src/hooks/use-surface-scale';
import {
MediaStream,
RTCIceCandidate,
RTCPeerConnection,
RTCSessionDescription,
} from 'react-native-webrtc';
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome';
import {getStream} from '../../../utils/VideoCallFunctions';
import {faVideo} from '@fortawesome/free-solid-svg-icons/index';
import firestore from '@react-native-firebase/firestore';
import {useRoute} from '@react-navigation/native';
const configuration = {iceServers: [{url: 'stun:stun.l.google.com:19302'}]};
export default function Cscreen() {
const scale = useSurfaceScale();
const [localStream, setLocalStream] = useState();
const [remoteStream, setRemoteStream] = useState();
const [gettingCall, setGettingCall] = useState(false);
const [isMuted, setIsMuted] = useState(false);
const [myKey, setMyKey] = useState('');
const pc = useRef();
const route = useRoute();
const {peerKey} = route.params || {};
const connecting = useRef(false);
useEffect(() => {
getData();
console.log('myKeys f el useEffect ', myKey);
const cRef = firestore()
.collection('signaling')
.doc('peers')
.collection('keys')
.doc(myKey);
console.log('myKey fel subscribe', myKey);
const subscribe = cRef.onSnapshot(snapshot => {
const data = snapshot.data();
// on answer start call
if (pc.current && !pc.current.remoteDescription && data && data.answer) {
pc.current.setRemoteDescription(new RTCSessionDescription(data.answer));
}
// If there is offer for chatId set the getting call flag
if (data && data.offer && !connecting.current) {
console.log('te7t el connecting');
setGettingCall(true);
}
//if one of the users hangs up without entering the call, the calls is terminated
if (!data) {
hangup();
}
});
// On delete of collection call hangup
// The other side has clicked on hangup
const subscribeDelete = cRef.onSnapshot(snapshot => {
if (!snapshot.exists) {
console.log('document does not exist, hangup normally');
hangup();
}
});
return () => {
subscribe();
subscribeDelete();
};
}, []);
const getData = async () => {
try {
const value = await AsyncStorage.getItem('myKey');
if (value !== null) {
console.log('myKey from storage:', value);
setMyKey(value);
}
} catch (e) {
console.log('Failed to fetch the data from storage:', e);
}
};
const switchCamera = () => {
localStream.getVideoTracks().forEach(track => track._switchCamera());
console.log('localStream.getVideoTracks()', localStream.getVideoTracks());
};
const switchAudio = () => {
localStream.getAudioTracks().forEach(track => {
track.enabled = !isMuted;
});
setIsMuted(!isMuted);
console.log('ismuted', isMuted);
console.log('localStream.audio()', localStream.getAudioTracks());
};
const setupWebrtc = async () => {
pc.current = new RTCPeerConnection(configuration);
console.log(' origin current: ', pc.current);
// Get the audio and video stream for the call
const stream = await getStream();
console.log('stream in setup', stream);
if (stream) {
setLocalStream(stream);
console.log(' t3addet el localstream ');
stream.getTracks().forEach(track => {
pc.current.addTrack(track, stream);
});
}
// Get the remote stream once it is available
console.log(' pc.current.ontrack ', pc.current.ontrack);
pc.current.ontrack = event => {
console.log('event.stream', event.streams);
setRemoteStream(event.streams[0]);
console.log('event.streams[0]', event.streams[0]);
};
};
const create = async () => {
connecting.current = true;
console.log('create');
// setup webrtc
await setupWebrtc();
// Document for the call
const cRef = firestore()
.collection('signaling')
.doc('peers')
.collection('keys');
collectIceCandidates(cRef, myKey, peerKey);
// Exchange the ICE candidates between the caller and callee
if (pc.current) {
console.log('pc.current', pc.current);
// Create the offer for the call
// Store the offer under the document
const offer = await pc.current.createOffer();
// Store the offer under the document
await cRef.doc(myKey).set({offer});
// Set the offer as the local description
await pc.current.setLocalDescription(offer);
console.log('Local description set:', pc.current.localDescription);
console.log('cRef setted ');
}
};
const join = async () => {
console.log('Joining call');
connecting.current = true;
setGettingCall(false);
const cRef = firestore()
.collection('signaling')
.doc('peers')
.collection('keys')
.doc(myKey);
const offerSnapshot = await cRef.get();
const offer = offerSnapshot.data().offer;
//console.log('offer ', offer);
if (offer) {
// setup webrtc
await setupWebrtc();
// Exchange the ICE candidate
// check the parameters, it's reversed. since joining part is callee
collectIceCandidates(cRef, peerKey, myKey);
if (pc.current) {
pc.current.setRemoteDescription(new RTCSessionDescription(offer));
// Create the answer for the call
// Update the document with answer
const cRef = firestore()
.collection('signaling')
.doc('peers')
.collection('keys')
.doc(peerKey);
const answer = await pc.current.createAnswer();
console.log('answer answer answer', answer);
pc.current.setLocalDescription(answer);
const cWithAnswer = {
answer: {
type: answer.type,
sdp: answer.sdp,
},
};
cRef.update(cWithAnswer);
}
}
};
/**
For disconnecting the call close the connection, release the stream
And delete the document for the call
*/
const hangup = async () => {
setGettingCall(false);
connecting.current = false;
streamCleanUp();
//firestoreCleanUp();
if (pc.current) {
pc.current.close();
}
};
// Helper function
const streamCleanUp = async () => {
if (localStream) {
localStream.getTracks().forEach(t => t.stop());
localStream.release();
}
setLocalStream(null);
setRemoteStream(null);
};
const firestoreCleanUp = async () => {
const cRef = firestore()
.collection('signaling')
.doc('peers')
.collection('keys');
if (cRef) {
const myDocRef = cRef.doc(myKey);
const myDocSnapshot = await myDocRef.get();
if (myDocSnapshot.exists && myDocSnapshot.get(peerKey)) {
await myDocRef.update({
[peerKey]: firestore.FieldValue.delete(),
offer: firestore.FieldValue.delete(),
});
}
}
const peerDocRef = cRef.doc(peerKey);
const peerDocSnapshot = await peerDocRef.get();
if (
peerDocSnapshot.exists
// && peerDocSnapshot.get(answer)
) {
await peerDocRef.update({
answer: firestore.FieldValue.delete(),
});
}
};
const collectIceCandidates = async (cRef, localName, remoteName) => {
const candidateDocRef = cRef.doc(localName);
console.log('candidateDocRef', candidateDocRef);
if (pc.current) {
// on new ICE candidate add it to firestore
console.log('pc.current candidateDocRef', pc.current.onicecandidate);
pc.current.onicecandidate = async event => {
if (event.candidate) {
console.log('event.candidate', event.candidate);
await candidateDocRef.update({
[remoteName]: firestore.FieldValue.arrayUnion(
event.candidate.toJSON(),
),
});
}
console.log('base donne updated');
};
}
// Get the ICE candidates added to firestore and update the local pc
const candidateCollectionRef = cRef.doc(localName);
console.log('second fct collectIce');
candidateCollectionRef.onSnapshot(snapshot => {
console.log('second fct collectIce snapshot');
const candidates = snapshot.data();
console.log('candidates', candidates);
if (candidates && candidates[remoteName]) {
candidates[remoteName].forEach(candidateData => {
console.log('te7t candidates remote');
const candidate = new RTCIceCandidate(candidateData);
console.log('candidate candidate', candidate);
pc.current
.addIceCandidate(candidate)
.then(() => console.log('Ice candidate added successfully!'))
.catch(error =>
console.error('Failed to add ice candidate:', error),
);
});
}
});
};
在这里输入
Thanks in advance
Any help would be appreciated