This commit is contained in:
wow22831 2024-10-28 01:34:24 +07:00
parent 8a9b66b1fd
commit 8c7b33c853
2 changed files with 82 additions and 18 deletions

View File

@ -6,6 +6,8 @@ import {
} from '@ionic/react'; } from '@ionic/react';
import { call as callIcon, close as hangUpIcon } from 'ionicons/icons'; 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 ExploreContainer: React.FC = () => {
const [callString, setCallString] = useState(""); // Здесь будет храниться IP-адрес получателя звонка const [callString, setCallString] = useState(""); // Здесь будет храниться IP-адрес получателя звонка
const [isEnable, setIsEnable] = useState(true); const [isEnable, setIsEnable] = useState(true);
@ -17,12 +19,11 @@ const ExploreContainer: React.FC = () => {
const [peerConnection, setPeerConnection] = useState<RTCPeerConnection | null>(null); const [peerConnection, setPeerConnection] = useState<RTCPeerConnection | null>(null);
const [remoteStream, setRemoteStream] = useState<MediaStream | null>(null); const [remoteStream, setRemoteStream] = useState<MediaStream | null>(null);
// Создаем RTCPeerConnection без использования ICE-серверов // Инициализация WebRTC соединения
useEffect(() => { useEffect(() => {
const pc = new RTCPeerConnection(); const pc = new RTCPeerConnection();
setPeerConnection(pc); setPeerConnection(pc);
// Получаем удаленные медиа-потоки
pc.ontrack = (event) => { pc.ontrack = (event) => {
const [stream] = event.streams; const [stream] = event.streams;
setRemoteStream(stream); setRemoteStream(stream);
@ -31,17 +32,41 @@ const ExploreContainer: React.FC = () => {
pc.onicecandidate = (event) => { pc.onicecandidate = (event) => {
if (event.candidate) { if (event.candidate) {
console.log('ICE Candidate:', event.candidate); socket.send(JSON.stringify({
// В локальной сети с фиксированными IP это обычно не требуется, но можно отправить кандидата вручную type: 'ice-candidate',
candidate: event.candidate,
target: callString,
}));
} }
}; };
return () => { return () => {
pc.close(); 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 () => { const makeCall = useCallback(async () => {
if (peerConnection && callString) { if (peerConnection && callString) {
setIsLoading(true); setIsLoading(true);
@ -49,16 +74,16 @@ const ExploreContainer: React.FC = () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
setLocalStream(stream); setLocalStream(stream);
// Добавляем треки к соединению
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
// Создаем SDP предложение для вызова
const offer = await peerConnection.createOffer(); const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer); await peerConnection.setLocalDescription(offer);
// Отправляем SDP предложение получателю (на callString, можно использовать HTTP запрос) socket.send(JSON.stringify({
console.log('SDP Offer:', offer); type: 'offer',
// Здесь можно использовать WebSocket или другой способ обмена SDP в локальной сети offer: offer,
target: callString,
}));
setIsLoading(false); setIsLoading(false);
setIsCallActive(true); setIsCallActive(true);
@ -72,7 +97,7 @@ const ExploreContainer: React.FC = () => {
} }
}, [peerConnection, callString]); }, [peerConnection, callString]);
// Принятие входящего звонка (ответ) // Принятие входящего звонка
const handleIncomingCall = useCallback(async (offer: RTCSessionDescriptionInit) => { const handleIncomingCall = useCallback(async (offer: RTCSessionDescriptionInit) => {
if (peerConnection) { if (peerConnection) {
try { try {
@ -80,16 +105,16 @@ const ExploreContainer: React.FC = () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
setLocalStream(stream); setLocalStream(stream);
// Добавляем треки к соединению
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
// Создаем SDP ответ
const answer = await peerConnection.createAnswer(); const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer); await peerConnection.setLocalDescription(answer);
// Отправляем SDP ответ инициатору socket.send(JSON.stringify({
console.log('SDP Answer:', answer); type: 'answer',
// Также отправляем SDP ответ инициатору через HTTP/WebSocket answer: answer,
target: callString,
}));
setIsCallActive(true); setIsCallActive(true);
startCallTimer(); startCallTimer();
@ -97,7 +122,7 @@ const ExploreContainer: React.FC = () => {
console.error('Ошибка обработки входящего вызова', err); console.error('Ошибка обработки входящего вызова', err);
} }
} }
}, [peerConnection]); }, [peerConnection, callString]);
// Завершение звонка // Завершение звонка
const endCall = useCallback(() => { const endCall = useCallback(() => {

View File

@ -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');