Advertisement
Guest User

Untitled

a guest
Jul 1st, 2022
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { Button } from '@mantine/core';
  2. import { io } from 'socket.io-client';
  3. import { v4 as generateUuid } from 'uuid';
  4.  
  5. interface Peer {
  6.   id: string;
  7.   consumerId?: string;
  8.   pc?: RTCPeerConnection;
  9. }
  10.  
  11. const upPeers = new Map<string, Peer>();
  12. const downPeers = new Map<string, RTCPeerConnection>();
  13.  
  14. let state = false;
  15.  
  16. const socket = io('http://localhost:8000');
  17.  
  18. const consume = async (p: Peer) => {
  19.   if (p.id === socket.id || upPeers.has(p.id)) return;
  20.   const consumerId = generateUuid();
  21.  
  22.   console.log('Consuming', p.id);
  23.  
  24.   const peer = upPeers.set(p.id, p).get(p.id);
  25.   if (!peer) return;
  26.  
  27.   peer.consumerId = consumerId;
  28.   const pc = new RTCPeerConnection({
  29.     iceServers: [
  30.       { urls: 'stun:stun.stunprotocol.org:3478' },
  31.       { urls: 'stun:stun.l.google.com:19302' },
  32.     ],
  33.   });
  34.  
  35.   const downPeer = downPeers.set(consumerId, pc).get(consumerId);
  36.   if (!downPeer) return;
  37.  
  38.   downPeer.addTransceiver('video', { direction: 'recvonly' });
  39.   downPeer.addTransceiver('audio', { direction: 'recvonly' });
  40.  
  41.   const offer = await downPeer.createOffer();
  42.   await downPeer.setLocalDescription(offer);
  43.  
  44.   downPeer.onicecandidate = ({ candidate }) => {
  45.     if (candidate && candidate.candidate && candidate.candidate.length > 0)
  46.       socket.emit('down_ice', { consumerId, candidate });
  47.   };
  48.  
  49.   downPeer.ontrack = (event) => {
  50.     const container = document.querySelector('#container');
  51.     if (!container) return;
  52.  
  53.     const video = document.querySelector<HTMLVideoElement>(`#down_${peer.id}`);
  54.     const remoteStream = event.streams[0];
  55.  
  56.     if (video) {
  57.       remoteStream.getTracks().forEach((track) => {
  58.         video.srcObject.addTrack(track);
  59.       });
  60.     } else {
  61.       const video = document.createElement('video');
  62.       video.id = `down_${peer.id}`;
  63.       video.srcObject = remoteStream;
  64.       video.autoplay = true;
  65.       video.muted = false;
  66.  
  67.       container.appendChild(video);
  68.     }
  69.   };
  70.  
  71.   socket.emit(
  72.     'down',
  73.     { id: peer.id, consumerId, offer },
  74.     (answer: RTCSessionDescriptionInit) => {
  75.       downPeer.setRemoteDescription(new RTCSessionDescription(answer));
  76.     },
  77.   );
  78. };
  79.  
  80. const join = async () => {
  81.   const localStream = await navigator.mediaDevices.getUserMedia({
  82.     audio: true,
  83.     video: {
  84.       mandatory: {
  85.         width: { min: 320 },
  86.         height: { min: 180 },
  87.       },
  88.       optional: [
  89.         { width: { max: 1280 } },
  90.         { frameRate: 30 },
  91.         { facingMode: 'user' },
  92.       ],
  93.     },
  94.   });
  95.  
  96.   const container = document.querySelector('#container');
  97.   if (!container) return;
  98.  
  99.   const video = document.createElement('video');
  100.   video.id = `up`;
  101.   video.srcObject = localStream;
  102.   video.autoplay = true;
  103.   video.muted = true;
  104.  
  105.   container.appendChild(video);
  106.  
  107.   const pc = new RTCPeerConnection({
  108.     iceServers: [
  109.       { urls: 'stun:stun.stunprotocol.org:3478' },
  110.       { urls: 'stun:stun.l.google.com:19302' },
  111.     ],
  112.   });
  113.  
  114.   pc.onicecandidate = ({ candidate }) => {
  115.     if (candidate && candidate.candidate && candidate.candidate.length > 0)
  116.       socket.emit('up_ice', candidate);
  117.   };
  118.  
  119.   pc.onnegotiationneeded = async () => {
  120.     const offer = await pc.createOffer();
  121.     await pc.setLocalDescription(offer);
  122.  
  123.     socket.emit(
  124.       'up',
  125.       offer,
  126.       ({
  127.         upPeers: peers,
  128.         answer,
  129.       }: {
  130.         upPeers: Peer[];
  131.         answer: RTCSessionDescriptionInit;
  132.       }) => {
  133.         pc.setRemoteDescription(new RTCSessionDescription(answer));
  134.  
  135.         peers.forEach(consume);
  136.         state = true;
  137.       },
  138.     );
  139.   };
  140.  
  141.   localStream.getTracks().forEach((track) => {
  142.     pc.addTrack(track, localStream);
  143.   });
  144. };
  145.  
  146. socket.on('newUp', (id) => {
  147.   if (state) consume({ id });
  148. });
  149.  
  150. socket.on('producerLeft', (id) => {
  151.   const client = upPeers.get(id);
  152.   if (!client?.consumerId) return;
  153.  
  154.   downPeers.delete(client.consumerId);
  155.   upPeers.delete(id);
  156.  
  157.   const video = document.querySelector<HTMLVideoElement>(`#other_${id}`);
  158.   if (!video) return;
  159.  
  160.   if (video.srcObject)
  161.     video.srcObject.getTracks().forEach((track) => track.stop());
  162.   video.remove();
  163. });
  164.  
  165. const Unite = () => {
  166.   return (
  167.     <div>
  168.       {!state ? (
  169.         <Button
  170.           onClick={() => {
  171.             join();
  172.           }}
  173.         >
  174.           Join
  175.         </Button>
  176.       ) : (
  177.         socket.id
  178.       )}
  179.       <div id="container" />
  180.     </div>
  181.   );
  182. };
  183.  
  184. export default Unite;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement