/* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' import React, { useRef } from 'react' export default function ChatNoServerWidget() { const localVideo = useRef(null) const remoteVideo = useRef(null) const localStream = useRef(null) const pc1 = useRef(null) const pc2 = useRef(null) const handleStart = async () => { console.log('Requesting local stream'); try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); console.log('Received local stream'); localVideo.current!.srcObject = stream; localStream.current = stream; } catch (e) { console.error(e) alert(`getUserMedia() error: ${(e as Error).name}`); } } function getName(pc: RTCPeerConnection) { return (pc === pc1.current) ? 'pc1' : 'pc2'; } function getOtherPc(pc: RTCPeerConnection) { return (pc === pc1.current) ? pc2.current : pc1.current; } async function onIceCandidate(pc: RTCPeerConnection, event: RTCPeerConnectionIceEvent) { 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)'}`); } function onAddIceCandidateSuccess(pc: RTCPeerConnection) { console.log(`${getName(pc)} addIceCandidate success`); } function onAddIceCandidateError(pc: RTCPeerConnection, error: any) { console.log(`${getName(pc)} failed to add ICE Candidate: ${error.toString()}`); } function onIceStateChange(pc: RTCPeerConnection, event: Event) { if (pc) { console.log(`${getName(pc)} ICE state: ${pc.iceConnectionState}`); console.log('ICE state change event: ', event); } } function gotRemoteStream(e: RTCTrackEvent) { if (remoteVideo.current!.srcObject !== e.streams[0]) { remoteVideo.current!.srcObject = e.streams[0]; console.log('pc2 received remote stream'); } } async function call() { console.log('Starting call'); const videoTracks = localStream.current!.getVideoTracks(); const audioTracks = localStream.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 = {}; console.log('RTCPeerConnection configuration:', configuration); pc1.current = new RTCPeerConnection(configuration); console.log('Created local peer connection object pc1'); pc1.current.addEventListener('icecandidate', e => onIceCandidate(pc1.current!, e)); pc2.current = new RTCPeerConnection(configuration); console.log('Created remote peer connection object pc2'); pc2.current.addEventListener('icecandidate', e => onIceCandidate(pc2.current!, e)); pc1.current.addEventListener('iceconnectionstatechange', e => onIceStateChange(pc1.current!, e)); pc2.current.addEventListener('iceconnectionstatechange', e => onIceStateChange(pc2.current!, e)); pc2.current.addEventListener('track', gotRemoteStream); localStream.current!.getTracks().forEach(track => pc1.current!.addTrack(track, localStream.current!)); console.log('Added local stream to pc1'); try { console.log('pc1 createOffer start'); const offer = await pc1.current.createOffer(); // const offer = await pc1.current.createOffer(offerOptions); await onCreateOfferSuccess(offer); } catch (e) { onCreateSessionDescriptionError(e); } } function onSetLocalSuccess(pc: RTCPeerConnection) { console.log(`${getName(pc)} setLocalDescription complete`); } function onSetRemoteSuccess(pc: RTCPeerConnection) { console.log(`${getName(pc)} setRemoteDescription complete`); } function onSetSessionDescriptionError(error: any) { console.log(`Failed to set session description: ${error.toString()}`); } async function onCreateOfferSuccess(desc: RTCSessionDescriptionInit) { console.log(`Offer from pc1\n${desc.sdp}`); console.log('pc1 setLocalDescription start'); try { await pc1.current!.setLocalDescription(desc); onSetLocalSuccess(pc1.current!); } catch (e) { onSetSessionDescriptionError(e); } console.log('pc2 setRemoteDescription start'); try { await pc2.current!.setRemoteDescription(desc); onSetRemoteSuccess(pc2.current!); } catch (e) { onSetSessionDescriptionError(e); } console.log('pc2 createAnswer start'); // Since the 'remote' side has no media stream we need // to pass in the right constraints in order for it to // accept the incoming offer of audio and video. try { const answer = await pc2.current!.createAnswer(); await onCreateAnswerSuccess(answer); } catch (e) { onCreateSessionDescriptionError(e); } } async function onCreateAnswerSuccess(desc: RTCSessionDescriptionInit) { console.log(`Answer from pc2:\n${desc.sdp}`); console.log('pc2 setLocalDescription start'); try { await pc2.current!.setLocalDescription(desc); onSetLocalSuccess(pc2.current!); } catch (e) { onSetSessionDescriptionError(e); } console.log('pc1 setRemoteDescription start'); try { await pc1.current!.setRemoteDescription(desc); onSetRemoteSuccess(pc1.current!); } catch (e) { onSetSessionDescriptionError(e); } } function onCreateSessionDescriptionError(error: any) { console.log(`Failed to create session description: ${error.toString()}`); } return (
) }