Буферизация ICE кандидатов (для избежания гонки)
This commit is contained in:
@@ -71,15 +71,40 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
const roleRef = useRef<CallRole | null>(null);
|
const roleRef = useRef<CallRole | null>(null);
|
||||||
const [sharedSecret, setSharedSecret] = useState<string>("");
|
const [sharedSecret, setSharedSecret] = useState<string>("");
|
||||||
const iceServersRef = useRef<RTCIceServer[]>([]);
|
const iceServersRef = useRef<RTCIceServer[]>([]);
|
||||||
|
const remoteAudioRef = useRef<HTMLAudioElement>(null);
|
||||||
|
const iceCandidatesBufferRef = useRef<RTCIceCandidate[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
/**
|
/**
|
||||||
* Нам нужно получить ICE серверы для установки соединения из разных сетей
|
* Нам нужно получить ICE серверы для установки соединения из разных сетей
|
||||||
* Получаем их от сервера
|
* Получаем их от сервера
|
||||||
*/
|
*/
|
||||||
let packet = new PacketIceServers();
|
let packet = new PacketIceServers();
|
||||||
send(packet);
|
send(packet);
|
||||||
}, []);
|
|
||||||
|
//debug
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
if(callState == CallState.ACTIVE){
|
||||||
|
if(peerConnectionRef.current){
|
||||||
|
const stats = await peerConnectionRef.current.getStats();
|
||||||
|
stats.forEach((report) => {
|
||||||
|
|
||||||
|
if (report.type === "inbound-rtp" && !report.isRemote) {
|
||||||
|
const kind = (report as any).kind || (report as any).mediaType;
|
||||||
|
const bytesReceived = (report as any).bytesReceived ?? 0;
|
||||||
|
const packetsReceived = (report as any).packetsReceived ?? 0;
|
||||||
|
const packetsLost = (report as any).packetsLost ?? 0;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`[inbound ${kind}] bytesReceived=${bytesReceived}, packetsReceived=${packetsReceived}, packetsLost=${packetsLost}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}, [callState, peerConnectionRef]);
|
||||||
|
|
||||||
usePacket(28, async (packet: PacketIceServers) => {
|
usePacket(28, async (packet: PacketIceServers) => {
|
||||||
let iceServers = packet.getIceServers();
|
let iceServers = packet.getIceServers();
|
||||||
@@ -118,6 +143,15 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
*/
|
*/
|
||||||
const sdp = JSON.parse(packet.getSdpOrCandidate());
|
const sdp = JSON.parse(packet.getSdpOrCandidate());
|
||||||
await peerConnectionRef.current?.setRemoteDescription(new RTCSessionDescription(sdp));
|
await peerConnectionRef.current?.setRemoteDescription(new RTCSessionDescription(sdp));
|
||||||
|
if(iceCandidatesBufferRef.current.length > 0){
|
||||||
|
/**
|
||||||
|
* У нас есть буферизированные ICE кандидаты, которые мы получили до установки удаленного описания, теперь мы можем их добавить в PeerConnection
|
||||||
|
*/
|
||||||
|
for(let i = 0; i < iceCandidatesBufferRef.current.length; i++){
|
||||||
|
await peerConnectionRef.current?.addIceCandidate(iceCandidatesBufferRef.current[i]);
|
||||||
|
}
|
||||||
|
iceCandidatesBufferRef.current = [];
|
||||||
|
}
|
||||||
info("Received WebRTC answer and set remote description");
|
info("Received WebRTC answer and set remote description");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -127,6 +161,14 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
*/
|
*/
|
||||||
const candidate = JSON.parse(packet.getSdpOrCandidate());
|
const candidate = JSON.parse(packet.getSdpOrCandidate());
|
||||||
console.info(candidate);
|
console.info(candidate);
|
||||||
|
if(peerConnectionRef.current?.remoteDescription == null){
|
||||||
|
/**
|
||||||
|
* Удаленное описание еще не установлено, буферизуем кандидата, чтобы добавить его после установки удаленного описания
|
||||||
|
*/
|
||||||
|
iceCandidatesBufferRef.current.push(new RTCIceCandidate(candidate));
|
||||||
|
info("Received WebRTC ICE candidate but remote description is not set yet, buffering candidate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
await peerConnectionRef.current?.addIceCandidate(new RTCIceCandidate(candidate));
|
await peerConnectionRef.current?.addIceCandidate(new RTCIceCandidate(candidate));
|
||||||
info("Received WebRTC ICE candidate and added to peer connection");
|
info("Received WebRTC ICE candidate and added to peer connection");
|
||||||
return;
|
return;
|
||||||
@@ -165,13 +207,7 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
/**
|
/**
|
||||||
* Сбросили звонок
|
* Сбросили звонок
|
||||||
*/
|
*/
|
||||||
setActiveCall("");
|
end();
|
||||||
setCallState(CallState.ENDED);
|
|
||||||
setShowCallView(false);
|
|
||||||
setSessionKeys(null);
|
|
||||||
setSharedSecret("");
|
|
||||||
setDuration(0);
|
|
||||||
roleRef.current = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(signalType == SignalType.CALL){
|
if(signalType == SignalType.CALL){
|
||||||
@@ -276,7 +312,12 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
* При получении медиа-трека с другой стороны
|
* При получении медиа-трека с другой стороны
|
||||||
*/
|
*/
|
||||||
console.info("TRACK RECV!!!!!");
|
console.info("TRACK RECV!!!!!");
|
||||||
|
if(remoteAudioRef.current){
|
||||||
|
console.info(event.streams);
|
||||||
|
remoteAudioRef.current.srcObject = event.streams[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Запрашиваем Аудио поток с микрофона и добавляем его в PeerConnection, чтобы другая сторона могла его получить и воспроизвести,
|
* Запрашиваем Аудио поток с микрофона и добавляем его в PeerConnection, чтобы другая сторона могла его получить и воспроизвести,
|
||||||
* когда мы установим WebRTC соединение
|
* когда мы установим WebRTC соединение
|
||||||
@@ -291,7 +332,7 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
* Отправляем свой оффер другой стороне
|
* Отправляем свой оффер другой стороне
|
||||||
*/
|
*/
|
||||||
let offer = await peerConnectionRef.current.createOffer();
|
let offer = await peerConnectionRef.current.createOffer();
|
||||||
peerConnectionRef.current.setLocalDescription(offer);
|
await peerConnectionRef.current.setLocalDescription(offer);
|
||||||
let offerSignal = new PacketWebRTC();
|
let offerSignal = new PacketWebRTC();
|
||||||
offerSignal.setSignalType(WebRTCSignalType.OFFER);
|
offerSignal.setSignalType(WebRTCSignalType.OFFER);
|
||||||
offerSignal.setSdpOrCandidate(JSON.stringify(offer));
|
offerSignal.setSdpOrCandidate(JSON.stringify(offer));
|
||||||
@@ -325,6 +366,11 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
packetSignal.setDst(activeCall);
|
packetSignal.setDst(activeCall);
|
||||||
packetSignal.setSignalType(SignalType.END_CALL);
|
packetSignal.setSignalType(SignalType.END_CALL);
|
||||||
send(packetSignal);
|
send(packetSignal);
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = () => {
|
||||||
|
peerConnectionRef.current?.close();
|
||||||
peerConnectionRef.current = null;
|
peerConnectionRef.current = null;
|
||||||
roomIdRef.current = "";
|
roomIdRef.current = "";
|
||||||
setActiveCall("");
|
setActiveCall("");
|
||||||
@@ -386,6 +432,7 @@ export function CallProvider(props : CallProviderProps) {
|
|||||||
return (
|
return (
|
||||||
<CallContext.Provider value={context}>
|
<CallContext.Provider value={context}>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
<audio ref={remoteAudioRef} autoPlay playsInline style={{ display: 'none' }} />
|
||||||
{showCallView && <Call context={context}></Call>}
|
{showCallView && <Call context={context}></Call>}
|
||||||
</CallContext.Provider>
|
</CallContext.Provider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export const SERVERS = [
|
export const SERVERS = [
|
||||||
//'wss://cdn.rosetta-im.com',
|
//'wss://cdn.rosetta-im.com',
|
||||||
//'ws://10.211.55.2:3000',
|
'ws://10.211.55.2:3000',
|
||||||
'ws://192.168.6.82:3000',
|
//'ws://192.168.6.82:3000',
|
||||||
//'wss://wss.rosetta.im'
|
//'wss://wss.rosetta.im'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user