diff --git a/src/components/ExploreContainer.tsx b/src/components/ExploreContainer.tsx index 9513127..73ce263 100644 --- a/src/components/ExploreContainer.tsx +++ b/src/components/ExploreContainer.tsx @@ -6,6 +6,8 @@ import { } from '@ionic/react'; import { call as callIcon, close as hangUpIcon } from 'ionicons/icons'; +const socket = new WebSocket('ws://192.168.0.160:8080'); // Адрес вашего WebSocket сервера + const ExploreContainer: React.FC = () => { const [callString, setCallString] = useState(""); // Здесь будет храниться IP-адрес получателя звонка const [isEnable, setIsEnable] = useState(true); @@ -17,12 +19,11 @@ const ExploreContainer: React.FC = () => { const [peerConnection, setPeerConnection] = useState(null); const [remoteStream, setRemoteStream] = useState(null); - // Создаем RTCPeerConnection без использования ICE-серверов + // Инициализация WebRTC соединения useEffect(() => { const pc = new RTCPeerConnection(); setPeerConnection(pc); - // Получаем удаленные медиа-потоки pc.ontrack = (event) => { const [stream] = event.streams; setRemoteStream(stream); @@ -31,17 +32,41 @@ const ExploreContainer: React.FC = () => { pc.onicecandidate = (event) => { if (event.candidate) { - console.log('ICE Candidate:', event.candidate); - // В локальной сети с фиксированными IP это обычно не требуется, но можно отправить кандидата вручную + socket.send(JSON.stringify({ + type: 'ice-candidate', + candidate: event.candidate, + target: callString, + })); } }; return () => { pc.close(); }; - }, []); + }, [callString]); - // Запуск вызова (инициатор соединения) + // Обработка входящих сообщений WebSocket + useEffect(() => { + socket.onmessage = async (event) => { + const data = JSON.parse(event.data); + + if (data.type === 'offer') { + await handleIncomingCall(data.offer); + } else if (data.type === 'answer') { + if (peerConnection) { + await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer)); + } + } else if (data.type === 'ice-candidate' && peerConnection) { + try { + await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate)); + } catch (error) { + console.error('Ошибка добавления ICE-кандидата', error); + } + } + }; + }, [peerConnection]); + + // Запуск вызова const makeCall = useCallback(async () => { if (peerConnection && callString) { setIsLoading(true); @@ -49,16 +74,16 @@ const ExploreContainer: React.FC = () => { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); setLocalStream(stream); - // Добавляем треки к соединению stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); - // Создаем SDP предложение для вызова const offer = await peerConnection.createOffer(); await peerConnection.setLocalDescription(offer); - // Отправляем SDP предложение получателю (на callString, можно использовать HTTP запрос) - console.log('SDP Offer:', offer); - // Здесь можно использовать WebSocket или другой способ обмена SDP в локальной сети + socket.send(JSON.stringify({ + type: 'offer', + offer: offer, + target: callString, + })); setIsLoading(false); setIsCallActive(true); @@ -72,7 +97,7 @@ const ExploreContainer: React.FC = () => { } }, [peerConnection, callString]); - // Принятие входящего звонка (ответ) + // Принятие входящего звонка const handleIncomingCall = useCallback(async (offer: RTCSessionDescriptionInit) => { if (peerConnection) { try { @@ -80,16 +105,16 @@ const ExploreContainer: React.FC = () => { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); setLocalStream(stream); - // Добавляем треки к соединению stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); - // Создаем SDP ответ const answer = await peerConnection.createAnswer(); await peerConnection.setLocalDescription(answer); - // Отправляем SDP ответ инициатору - console.log('SDP Answer:', answer); - // Также отправляем SDP ответ инициатору через HTTP/WebSocket + socket.send(JSON.stringify({ + type: 'answer', + answer: answer, + target: callString, + })); setIsCallActive(true); startCallTimer(); @@ -97,7 +122,7 @@ const ExploreContainer: React.FC = () => { console.error('Ошибка обработки входящего вызова', err); } } - }, [peerConnection]); + }, [peerConnection, callString]); // Завершение звонка const endCall = useCallback(() => { diff --git a/src/server/websocket-server.js b/src/server/websocket-server.js new file mode 100644 index 0000000..6e30866 --- /dev/null +++ b/src/server/websocket-server.js @@ -0,0 +1,39 @@ +// Установите Node.js и ws с помощью команды: npm install ws +const WebSocket = require('ws'); + +const server = new WebSocket.Server({ port: 8080 }); +const clients = {}; + +server.on('connection', (socket) => { + socket.on('message', (message) => { + const data = JSON.parse(message); + switch (data.type) { + case 'register': + clients[data.name] = socket; + console.log(`Клиент ${data.name} подключен`); + break; + case 'offer': + case 'answer': + case 'ice-candidate': + const targetSocket = clients[data.target]; + if (targetSocket) { + targetSocket.send(JSON.stringify(data)); + } else { + console.log(`Целевой клиент ${data.target} не найден`); + } + break; + } + }); + + socket.on('close', () => { + for (let name in clients) { + if (clients[name] === socket) { + console.log(`Клиент ${name} отключен`); + delete clients[name]; + break; + } + } + }); +}); + +console.log('WebSocket сервер запущен на ws://192.168.0.160:8080');