'use client' /* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useEffect, useRef, useState } from 'react' // https://www.baeldung.com/webrtc export default function WebRTComponent() { const WSRef = useRef(undefined) const videoRef1 = useRef(null) const localStreamRef1 = useRef(null) const [offers, setOffers] = useState([]) const peerConnection = useRef(undefined) const dataChannel = useRef(undefined) const send = (message: any) => WSRef.current!.send(JSON.stringify(message)); const onWSMessage = async (message: MessageEvent) => { console.log(`Received : `, message.data) const parsed = JSON.parse(message.data) switch (parsed.type) { case 'Offers': // setOffers(o => parsed.data as RTCSessionDescriptionInit[]) console.log('parsed.data',parsed.data) await acceptOffer(parsed.data) // await acceptOffer(parsed.data[parsed.data.length - 1]) break; case 'Answers': console.log(`Answers:`,parsed.data) peerConnection.current! .setRemoteDescription(new RTCSessionDescription({ ...parsed.data.sdp })) .catch((err) => console.error(err)); // break; } } const handleConectWS = async () => { WSRef.current = new WebSocket('ws://localhost:4000/socket'); WSRef.current.onopen = async function (event) { peerConnection.current = new RTCPeerConnection(undefined) // <-- Later add Stun servers as backup await setup() } WSRef.current.onmessage = async (ev) => onWSMessage(ev) } // 1. Get user media const Start = async () => { console.log('Requesting local stream'); const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); console.log(`Start Local Stream`) if (!videoRef1.current) console.error(`Video not yet available`) videoRef1.current!.srcObject = stream localStreamRef1.current = stream; console.log(`Set local stream`) } const joinServer = async () => { const configuration = {}; console.log('RTCPeerConnection configuration:', configuration); peerConnection.current = new RTCPeerConnection(configuration) peerConnection.current.createOffer().then(offer => { send({ type: 'OfferSDP', data: offer }) peerConnection.current?.setLocalDescription(offer) }) peerConnection.current.onicecandidate = function (event) { console.log(`Received ICE Candidate :`, event) } // pc.addEventListener('icecandidate', e => console.log(`icecandidate`, pc, e)); } const acceptOffer = async (recv: any) => { console.log(`acceptOffer`, recv) peerConnection.current!.setRemoteDescription(new RTCSessionDescription(recv)) .then(() => peerConnection.current!.createAnswer()) .then((answer) => peerConnection.current!.setLocalDescription(answer)) .then(() => send({ type: 'AnswerSDP', data: { sdp: peerConnection.current!.localDescription } })) .catch((err) => console.error('Failed to handle offer', err)); } // 2. Make call const makeCall = () => { // Get available streams const videoTracks = localStreamRef1.current!.getVideoTracks(); const audioTracks = localStreamRef1.current!.getAudioTracks(); if (videoTracks.length > 0) { console.log(`Using video device: ${videoTracks[0].label}`); } if (audioTracks.length > 0) { console.log(`Using audio device: ${audioTracks[0].label}`); } const configuration = {}; // 3. Start WebRTC console.log('RTCPeerConnection configuration:', configuration); // const pc1 = new RTCPeerConnection(configuration); // console.log('Created local peer connection object pc1'); // pc1.addEventListener('icecandidate', e => onIceCandidate(pc1, e)); // const pc2 = new RTCPeerConnection(configuration); // console.log('Created remote peer connection object pc2'); // pc2.addEventListener('icecandidate', e => onIceCandidate(pc2, e)); // pc1.addEventListener('iceconnectionstatechange', e => onIceStateChange(pc1, e)); // pc2.addEventListener('iceconnectionstatechange', e => onIceStateChange(pc2, e)); // pc2.addEventListener('track', gotRemoteStream); } // 4. On ICE Candidate // const onIceCandidate = async (peerConnection: RTCPeerConnection, e: Event) => { // try { // await(getOtherPc(pc).addIceCandidate(event.candidate)); // onAddIceCandidateSuccess(pc); // } catch (e) { // onAddIceCandidateError(pc, e); // } // console.log(`${getName(pc)} ICE candidate:\n${event.candidate ? event.candidate.candidate : '(null)'}`); // } async function setup() { // 1. Get local media stream // await Start() // 2. Join WS Server const handleJoin = () => { send({ type: 'Join' }) } handleJoin() } useEffect(() => { handleConectWS() // const load = async () => { // WSRef.current.onmessage = (ev) => { // // '{"event":"candidate","data":{"candidate":"candidate:1041930304 1 udp 2113937151 b7178aee-2d1d-4762-b709-1b25cf436cb5.local 61551 typ host generation 0 ufrag bEe6 network-cost 999","sdpMid":"0","sdpMLineIndex":0,"usernameFragment":"bEe6"}}' // const data = JSON.parse(ev.data) // // console.log(`Recevied WS : `, Object.keys(data)) // console.log(`Recevied WS : `, data.event) // switch (data.event) { // case 'offer': // console.log(`Check foreign offer`, data.data) // // Need to handle answer here // peerConnection.current.setRemoteDescription(new RTCSessionDescription({ sdp: data.data.sdp, type: 'offer' })) // .then(() => peerConnection.current.createAnswer()) // .then((answer) => peerConnection.current.setLocalDescription(answer)) // .then(() => send({ event: 'answer', data: { sdp: peerConnection.current.localDescription } })) // .catch((err) => console.error('Failed to handle offer', err)); // break; // case 'answer': // console.log(`Check foreign answer`, data.data) // peerConnection.current.setRemoteDescription(new RTCSessionDescription({ ...data.data.sdp })).catch((err) => console.error(err)); // // break; // case 'candidate': // console.log(`Check foreign candidate`, { ...data.data }) // if (data.data.candidate) { // peerConnection.current.addIceCandidate(new RTCIceCandidate({ ...data.data })).catch((err) => console.warn('Bad candidate', err)); // } // break; // } // } // } // load() }, []) return (
WebRTCChat
) }