diff --git a/src/components/ExploreContainer.tsx b/src/components/ExploreContainer.tsx index dd7807b..9513127 100644 --- a/src/components/ExploreContainer.tsx +++ b/src/components/ExploreContainer.tsx @@ -2,99 +2,120 @@ import React, { useState, useEffect, useCallback } from 'react'; import './ExploreContainer.css'; import InputContainer from './Input'; import { - IonButton, IonContent, IonFooter, IonToolbar, IonText, IonModal, IonIcon + IonButton, IonContent, IonText, IonModal, IonIcon } from '@ionic/react'; import { call as callIcon, close as hangUpIcon } from 'ionicons/icons'; -import Peer, { MediaConnection } from 'peerjs'; const ExploreContainer: React.FC = () => { - const [callString, setCallString] = useState(""); + const [callString, setCallString] = useState(""); // Здесь будет храниться IP-адрес получателя звонка const [isEnable, setIsEnable] = useState(true); - const [peer, setPeer] = useState(null); const [localStream, setLocalStream] = useState(null); - const [connectionInfo, setConnectionInfo] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isCallActive, setIsCallActive] = useState(false); const [callDuration, setCallDuration] = useState(0); const [callInterval, setCallInterval] = useState(null); - const [currentCallId, setCurrentCallId] = useState(null); + const [peerConnection, setPeerConnection] = useState(null); + const [remoteStream, setRemoteStream] = useState(null); + // Создаем RTCPeerConnection без использования ICE-серверов useEffect(() => { - const initializePeer = () => { - const newPeer = new Peer({ debug: 3 }); - setPeer(newPeer); + const pc = new RTCPeerConnection(); + setPeerConnection(pc); - newPeer.on('open', (id) => { - console.log(`Peer успешно открыт с ID: ${id}`); - setConnectionInfo(id); - }); - - newPeer.on('call', (call: MediaConnection) => handleIncomingCall(call)); - newPeer.on('error', (err) => console.error('Ошибка Peer:', err)); - - return () => { - newPeer.destroy(); - }; + // Получаем удаленные медиа-потоки + pc.ontrack = (event) => { + const [stream] = event.streams; + setRemoteStream(stream); + playAudio(stream); }; - const cleanup = initializePeer(); - return cleanup; + pc.onicecandidate = (event) => { + if (event.candidate) { + console.log('ICE Candidate:', event.candidate); + // В локальной сети с фиксированными IP это обычно не требуется, но можно отправить кандидата вручную + } + }; + + return () => { + pc.close(); + }; }, []); - const handleIncomingCall = useCallback((call: MediaConnection) => { - console.log('Получен входящий звонок'); - setCurrentCallId(call.peer); - navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => { - setLocalStream(stream); - call.answer(stream); - call.on('stream', (remoteStream: MediaStream) => { - console.log('Получен удалённый поток'); - playAudio(remoteStream); - startCallTimer(); - setIsCallActive(true); - }); - }).catch((err) => { - console.error('Не удалось получить локальный поток для ответа', err); - }); - }, []); - - const makeCall = useCallback(() => { - if (peer && callString) { + // Запуск вызова (инициатор соединения) + const makeCall = useCallback(async () => { + if (peerConnection && callString) { setIsLoading(true); - console.log(`Попытка звонка на: ${callString}`); - navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => { + try { + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); setLocalStream(stream); - const call = peer.call(callString, stream); - setCurrentCallId(callString); - call.on('stream', (remoteStream: MediaStream) => { - console.log('Получен удалённый поток во время вызова'); - playAudio(remoteStream); - setIsLoading(false); - startCallTimer(); - setIsCallActive(true); - }); - }).catch((err) => { + + // Добавляем треки к соединению + 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 в локальной сети + + setIsLoading(false); + setIsCallActive(true); + startCallTimer(); + } catch (err) { console.error('Не удалось получить локальный поток', err); setIsLoading(false); - }); + } } else { - console.warn('Звонок невозможен: отсутствует Peer или callString'); + console.warn('Звонок невозможен: отсутствует соединение или IP-адрес'); } - }, [peer, callString]); + }, [peerConnection, callString]); + // Принятие входящего звонка (ответ) + const handleIncomingCall = useCallback(async (offer: RTCSessionDescriptionInit) => { + if (peerConnection) { + try { + await peerConnection.setRemoteDescription(new RTCSessionDescription(offer)); + 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 + + setIsCallActive(true); + startCallTimer(); + } catch (err) { + console.error('Ошибка обработки входящего вызова', err); + } + } + }, [peerConnection]); + + // Завершение звонка const endCall = useCallback(() => { if (localStream) { localStream.getTracks().forEach(track => track.stop()); } + if (peerConnection) { + peerConnection.close(); + } setIsCallActive(false); setIsEnable(true); if (callInterval) { clearInterval(callInterval); } setCallDuration(0); - setCurrentCallId(null); - }, [localStream, callInterval]); + }, [localStream, peerConnection, callInterval]); + // Таймер звонка const startCallTimer = useCallback(() => { const interval = setInterval(() => { setCallDuration(prevDuration => prevDuration + 1); @@ -102,6 +123,7 @@ const ExploreContainer: React.FC = () => { setCallInterval(interval); }, []); + // Воспроизведение аудио потока const playAudio = useCallback((stream: MediaStream) => { const audioElement = document.createElement('audio'); audioElement.srcObject = stream; @@ -112,57 +134,34 @@ const ExploreContainer: React.FC = () => { }); }, []); - const copyPeerId = useCallback(() => { - if (connectionInfo) { - navigator.clipboard.writeText(connectionInfo) - .then(() => { - console.log('Peer ID скопирован в буфер обмена'); - }) - .catch((err) => { - console.error('Не удалось скопировать Peer ID', err); - }); - } - }, [connectionInfo]); - return ( - <> - -
-
- Ваш Peer ID: {connectionInfo} - -
-
- - - + +
+
+ + + + +
+
+ + + +
+ Звонок на IP: {callString} + {Math.floor(callDuration / 60)}:{callDuration % 60} + +
-
- - {/* Модальное окно для звонка */} - - -
- {/* Добавляем гифку */} - Monkey with Drone - Peer ID: {currentCallId} - {Math.floor(callDuration / 60)}:{callDuration % 60} - -
-
-
- - + + + ); }; -export default ExploreContainer; \ No newline at end of file +export default ExploreContainer;