Обмен SDP, создание комнаты, улучшенная организация кода

This commit is contained in:
RoyceDa
2026-03-14 15:28:01 +02:00
parent e79282755b
commit ca36a8d818
2 changed files with 177 additions and 10 deletions

View File

@@ -1,11 +1,12 @@
import { Call } from "@/app/components/Call/Call";
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
import { createContext, useEffect, useRef, useState } from "react";
import { createContext, useRef, useState } from "react";
import nacl from 'tweetnacl';
import { useSender } from "../ProtocolProvider/useSender";
import { PacketSignal, SignalType } from "../ProtocolProvider/protocol/packets/packet.signal";
import { PacketSignalPeer, SignalType } from "../ProtocolProvider/protocol/packets/packet.signal.peer";
import { usePacket } from "../ProtocolProvider/usePacket";
import { usePublicKey } from "../AccountProvider/usePublicKey";
import { PacketWebRTC, WebRTCSignalType } from "../ProtocolProvider/protocol/packets/packet.webrtc";
export interface CallContextValue {
@@ -64,15 +65,40 @@ export function CallProvider(props : CallProviderProps) {
const send = useSender();
const publicKey = usePublicKey();
const peerConnectionRef = useRef<RTCPeerConnection | null>(null);
const roomIdRef = useRef<string>("");
const roleRef = useRef<CallRole | null>(null);
const [sharedSecret, setSharedSecret] = useState<string>("");
useEffect(() => {
console.info("TRACE -> ", sharedSecret)
}, [sharedSecret]);
usePacket(27, async (packet: PacketWebRTC) => {
if(!activeCall || callState != CallState.WEB_RTC_EXCHANGE){
/**
* Нет активного звонка или мы не на стадии обмена WebRTC сигналами, игнорируем
*/
return;
}
const signalType = packet.getSignalType();
if(signalType == WebRTCSignalType.ANSWER){
/**
* Другая сторона (сервер SFU) отправил нам SDP ответ на наш оффер
*/
const sdp = JSON.parse(packet.getSdpOrCandidate());
await peerConnectionRef.current?.setRemoteDescription(new RTCSessionDescription(sdp));
info("Received WebRTC answer and set remote description");
return;
}
if(signalType == WebRTCSignalType.ICE_CANDIDATE){
/**
* Другая сторона отправила нам ICE кандидата для установления WebRTC соединения
*/
const candidate = JSON.parse(packet.getSdpOrCandidate());
await peerConnectionRef.current?.addIceCandidate(new RTCIceCandidate(candidate));
info("Received WebRTC ICE candidate and added to peer connection");
return;
}
}, [activeCall, sessionKeys, callState]);
usePacket(26, (packet: PacketSignal) => {
usePacket(26, async (packet: PacketSignalPeer) => {
const signalType = packet.getSignalType();
if(activeCall){
/**
@@ -123,13 +149,19 @@ export function CallProvider(props : CallProviderProps) {
/**
* Нам нужно отправить свой публичный ключ другой стороне, чтобы она тоже могла создать общую секретную сессию
*/
const signalPacket = new PacketSignal();
const signalPacket = new PacketSignalPeer();
signalPacket.setSrc(publicKey);
signalPacket.setDst(packet.getSrc());
signalPacket.setSignalType(SignalType.KEY_EXCHANGE);
signalPacket.setSharedPublic(Buffer.from(sessionKeys.publicKey).toString('hex'));
send(signalPacket);
setCallState(CallState.WEB_RTC_EXCHANGE);
/**
* Создаем комнату на сервере SFU, комнату создает звонящий
*/
let webRtcSignal = new PacketSignalPeer();
webRtcSignal.setSignalType(SignalType.CREATE_ROOM);
send(webRtcSignal);
}
if(signalType == SignalType.KEY_EXCHANGE && roleRef.current == CallRole.CALLEE){
console.info("EXCHANGE SIGNAL RECEIVED, CALLEE ROLE");
@@ -152,6 +184,32 @@ export function CallProvider(props : CallProviderProps) {
setSharedSecret(Buffer.from(computedSharedSecret).toString('hex'));
setCallState(CallState.WEB_RTC_EXCHANGE);
}
if(signalType == SignalType.CREATE_ROOM) {
/**
* Создана комната для обмена WebRTC потоками
*/
roomIdRef.current = packet.getRoomId();
info("WebRTC room created with id: " + packet.getRoomId());
/**
* Нужно отправить свой SDP оффер другой стороне, чтобы установить WebRTC соединение
*/
peerConnectionRef.current = new RTCPeerConnection({
//Experemental
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
/**
* Отправляем свой оффер другой стороне
*/
let offer = await peerConnectionRef.current.createOffer();
peerConnectionRef.current.setLocalDescription(offer);
let offerSignal = new PacketWebRTC();
offerSignal.setSignalType(WebRTCSignalType.OFFER);
offerSignal.setSdpOrCandidate(JSON.stringify(offer));
send(offerSignal);
return;
}
}, [activeCall, sessionKeys]);
const generateSessionKeys = () => {
@@ -165,7 +223,7 @@ export function CallProvider(props : CallProviderProps) {
setActiveCall(dialog);
setCallState(CallState.CONNECTING);
setShowCallView(true);
const signalPacket = new PacketSignal();
const signalPacket = new PacketSignalPeer();
signalPacket.setSrc(publicKey);
signalPacket.setDst(dialog);
signalPacket.setSignalType(SignalType.CALL);
@@ -174,12 +232,13 @@ export function CallProvider(props : CallProviderProps) {
}
const close = () => {
const packetSignal = new PacketSignal();
const packetSignal = new PacketSignalPeer();
packetSignal.setSrc(publicKey);
packetSignal.setDst(activeCall);
packetSignal.setSignalType(SignalType.END_CALL);
send(packetSignal);
peerConnectionRef.current = null;
roomIdRef.current = "";
setActiveCall("");
setCallState(CallState.ENDED);
setShowCallView(false);
@@ -199,7 +258,7 @@ export function CallProvider(props : CallProviderProps) {
* Звонок принят, генерируем ключи для сессии и отправляем их другой стороне для установления защищенного канала связи
*/
const keys = generateSessionKeys();
const signalPacket = new PacketSignal();
const signalPacket = new PacketSignalPeer();
signalPacket.setSrc(publicKey);
signalPacket.setDst(activeCall);
signalPacket.setSignalType(SignalType.KEY_EXCHANGE);