|
import { useEffect, useRef } from "react"; |
|
import { io, Socket } from "socket.io-client"; |
|
|
|
export function useGameSocket(gameId: string) { |
|
const socketRef = useRef<Socket | null>(null); |
|
const peerConnectionRef = useRef<RTCPeerConnection | null>(null); |
|
|
|
useEffect(() => { |
|
|
|
socketRef.current = io("http://localhost:5001", { |
|
path: "/", |
|
query: { gameId }, |
|
}); |
|
|
|
|
|
const configuration = { |
|
iceServers: [{ urls: "stun:stun.l.google.com:19302" }], |
|
}; |
|
peerConnectionRef.current = new RTCPeerConnection(configuration); |
|
|
|
|
|
socketRef.current.on("offer", async (offer: RTCSessionDescriptionInit) => { |
|
if (!peerConnectionRef.current) return; |
|
await peerConnectionRef.current.setRemoteDescription( |
|
new RTCSessionDescription(offer) |
|
); |
|
const answer = await peerConnectionRef.current.createAnswer(); |
|
await peerConnectionRef.current.setLocalDescription(answer); |
|
socketRef.current?.emit("answer", answer); |
|
}); |
|
|
|
socketRef.current.on( |
|
"answer", |
|
async (answer: RTCSessionDescriptionInit) => { |
|
if (!peerConnectionRef.current) return; |
|
await peerConnectionRef.current.setRemoteDescription( |
|
new RTCSessionDescription(answer) |
|
); |
|
} |
|
); |
|
|
|
socketRef.current.on( |
|
"candidate", |
|
async (candidate: RTCIceCandidateInit) => { |
|
if (!peerConnectionRef.current) return; |
|
await peerConnectionRef.current.addIceCandidate( |
|
new RTCIceCandidate(candidate) |
|
); |
|
} |
|
); |
|
|
|
|
|
peerConnectionRef.current.onicecandidate = (event) => { |
|
if (event.candidate) { |
|
socketRef.current?.emit("candidate", event.candidate); |
|
} |
|
}; |
|
|
|
|
|
return () => { |
|
if (socketRef.current) { |
|
socketRef.current.disconnect(); |
|
} |
|
if (peerConnectionRef.current) { |
|
peerConnectionRef.current.close(); |
|
} |
|
}; |
|
}, [gameId]); |
|
|
|
|
|
const startCall = async (stream: MediaStream) => { |
|
if (!peerConnectionRef.current || !socketRef.current) return; |
|
|
|
|
|
stream.getTracks().forEach((track) => { |
|
if (!peerConnectionRef.current) return; |
|
peerConnectionRef.current.addTrack(track, stream); |
|
}); |
|
|
|
|
|
const offer = await peerConnectionRef.current.createOffer(); |
|
await peerConnectionRef.current.setLocalDescription(offer); |
|
socketRef.current.emit("offer", offer); |
|
}; |
|
|
|
|
|
const handleIncomingAudio = (onTrack: (stream: MediaStream) => void) => { |
|
if (!peerConnectionRef.current) return; |
|
|
|
peerConnectionRef.current.ontrack = (event) => { |
|
onTrack(event.streams[0]); |
|
}; |
|
}; |
|
|
|
return { |
|
startCall, |
|
handleIncomingAudio, |
|
socket: socketRef.current, |
|
peerConnection: peerConnectionRef.current, |
|
}; |
|
} |
|
|