├── aula 1 └── frontend │ ├── .eslintrc.json │ ├── src │ ├── app │ │ ├── globals.css │ │ ├── favicon.ico │ │ ├── page.tsx │ │ ├── layout.tsx │ │ └── room │ │ │ └── [id] │ │ │ └── page.tsx │ ├── components │ │ ├── Container.tsx │ │ ├── Button.tsx │ │ ├── Create.tsx │ │ ├── Header.tsx │ │ ├── Join.tsx │ │ ├── Input.tsx │ │ ├── Chat.tsx │ │ ├── FormWrapper.tsx │ │ └── Footer.tsx │ └── Icons │ │ ├── index.ts │ │ ├── Phone.tsx │ │ ├── Computer.tsx │ │ ├── Mic.tsx │ │ ├── Camera.tsx │ │ ├── Vercel.tsx │ │ ├── NoComputer.tsx │ │ ├── NoMic.tsx │ │ ├── NoCamera.tsx │ │ ├── Next.tsx │ │ └── Logo.tsx │ ├── public │ ├── send.png │ ├── vercel.svg │ ├── computer.svg │ ├── no_computer.svg │ ├── phone.svg │ ├── next.svg │ ├── camera.svg │ ├── no_camera.svg │ ├── mic.svg │ ├── no_mic.svg │ └── logo.svg │ ├── next.config.mjs │ ├── postcss.config.js │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ ├── tailwind.config.ts │ └── README.md ├── aula 2 ├── frontend │ ├── .eslintrc.json │ ├── src │ │ ├── app │ │ │ ├── globals.css │ │ │ ├── favicon.ico │ │ │ ├── page.tsx │ │ │ ├── layout.tsx │ │ │ └── room │ │ │ │ └── [id] │ │ │ │ └── page.tsx │ │ ├── components │ │ │ ├── Container.tsx │ │ │ ├── Button.tsx │ │ │ ├── Header.tsx │ │ │ ├── Input.tsx │ │ │ ├── Join.tsx │ │ │ ├── Create.tsx │ │ │ ├── FormWrapper.tsx │ │ │ ├── Footer.tsx │ │ │ └── Chat.tsx │ │ ├── Icons │ │ │ ├── index.ts │ │ │ ├── Phone.tsx │ │ │ ├── Computer.tsx │ │ │ ├── Mic.tsx │ │ │ ├── Camera.tsx │ │ │ ├── Vercel.tsx │ │ │ ├── NoComputer.tsx │ │ │ ├── NoMic.tsx │ │ │ ├── NoCamera.tsx │ │ │ ├── Next.tsx │ │ │ └── Logo.tsx │ │ └── contexts │ │ │ └── SocketContext.tsx │ ├── public │ │ ├── send.png │ │ ├── vercel.svg │ │ ├── computer.svg │ │ ├── no_computer.svg │ │ ├── phone.svg │ │ ├── next.svg │ │ ├── camera.svg │ │ ├── no_camera.svg │ │ ├── mic.svg │ │ ├── no_mic.svg │ │ └── logo.svg │ ├── next.config.mjs │ ├── postcss.config.js │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ ├── tailwind.config.ts │ └── README.md └── backend │ ├── src │ ├── main.ts │ └── app.ts │ ├── package.json │ └── tsconfig.json ├── aula 3 ├── frontend │ ├── .eslintrc.json │ ├── public │ │ ├── send.png │ │ ├── vercel.svg │ │ ├── computer.svg │ │ ├── no_computer.svg │ │ ├── phone.svg │ │ ├── next.svg │ │ ├── camera.svg │ │ ├── no_camera.svg │ │ ├── mic.svg │ │ ├── no_mic.svg │ │ └── logo.svg │ ├── src │ │ ├── app │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── page.tsx │ │ │ ├── layout.tsx │ │ │ └── room │ │ │ │ └── [id] │ │ │ │ └── page.tsx │ │ ├── components │ │ │ ├── Container.tsx │ │ │ ├── Button.tsx │ │ │ ├── Header.tsx │ │ │ ├── Input.tsx │ │ │ ├── Create.tsx │ │ │ ├── Join.tsx │ │ │ ├── FormWrapper.tsx │ │ │ ├── Chat.tsx │ │ │ └── Footer.tsx │ │ ├── Icons │ │ │ ├── index.ts │ │ │ ├── Phone.tsx │ │ │ ├── Computer.tsx │ │ │ ├── Mic.tsx │ │ │ ├── Camera.tsx │ │ │ ├── Vercel.tsx │ │ │ ├── NoComputer.tsx │ │ │ ├── NoMic.tsx │ │ │ ├── NoCamera.tsx │ │ │ ├── Next.tsx │ │ │ └── Logo.tsx │ │ └── contexts │ │ │ └── SocketContext.tsx │ ├── next.config.mjs │ ├── postcss.config.js │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ ├── tailwind.config.ts │ └── README.md └── backend │ ├── src │ ├── main.ts │ └── app.ts │ ├── package.json │ └── tsconfig.json └── README.md /aula 1/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /aula 2/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /aula 3/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /aula 1/frontend/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /aula 2/frontend/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /aula 1/frontend/public/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroCodeBR/semana-heroi-03/HEAD/aula 1/frontend/public/send.png -------------------------------------------------------------------------------- /aula 2/frontend/public/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroCodeBR/semana-heroi-03/HEAD/aula 2/frontend/public/send.png -------------------------------------------------------------------------------- /aula 3/frontend/public/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroCodeBR/semana-heroi-03/HEAD/aula 3/frontend/public/send.png -------------------------------------------------------------------------------- /aula 1/frontend/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroCodeBR/semana-heroi-03/HEAD/aula 1/frontend/src/app/favicon.ico -------------------------------------------------------------------------------- /aula 2/frontend/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroCodeBR/semana-heroi-03/HEAD/aula 2/frontend/src/app/favicon.ico -------------------------------------------------------------------------------- /aula 3/frontend/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HeroCodeBR/semana-heroi-03/HEAD/aula 3/frontend/src/app/favicon.ico -------------------------------------------------------------------------------- /aula 2/backend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { App } from './app'; 2 | 3 | const app = new App(); 4 | 5 | app.listen(); 6 | app.listenSocket(); 7 | -------------------------------------------------------------------------------- /aula 3/backend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { App } from './app'; 2 | 3 | const app = new App(); 4 | 5 | app.listen(); 6 | app.listenSocket(); 7 | -------------------------------------------------------------------------------- /aula 1/frontend/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /aula 1/frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /aula 2/frontend/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /aula 2/frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /aula 3/frontend/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /aula 3/frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /aula 1/frontend/src/components/Container.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export default function Container({ children }: { children: ReactNode }) { 4 | return
{children}
; 5 | } 6 | -------------------------------------------------------------------------------- /aula 2/frontend/src/components/Container.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export default function Container({ children }: { children: ReactNode }) { 4 | return
{children}
; 5 | } 6 | -------------------------------------------------------------------------------- /aula 3/frontend/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .mirror-mode { 6 | -ms-transform: scaleX(-1); 7 | -webkit-transform: scaleX(-1); 8 | transform: scaleX(-1); 9 | 10 | } -------------------------------------------------------------------------------- /aula 3/frontend/src/components/Container.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export default function Container({ children }: { children: ReactNode }) { 4 | return
{children}
; 5 | } 6 | -------------------------------------------------------------------------------- /aula 1/frontend/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | interface IButton { 2 | title: string; 3 | type: 'button' | 'submit' | 'reset'; 4 | } 5 | export default function Button({ title, type }: IButton) { 6 | return ( 7 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /aula 2/frontend/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | interface IButton { 2 | title: string; 3 | type: 'button' | 'submit' | 'reset'; 4 | } 5 | export default function Button({ title, type }: IButton) { 6 | return ( 7 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /aula 3/frontend/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | interface IButton { 2 | title: string; 3 | type: 'button' | 'submit' | 'reset'; 4 | } 5 | export default function Button({ title, type }: IButton) { 6 | return ( 7 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /aula 1/frontend/src/components/Create.tsx: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | import Button from './Button'; 3 | import { Input } from './Input'; 4 | 5 | export default function CreateRoom() { 6 | const name = useRef(null); 7 | 8 | return ( 9 | <> 10 | 11 | 12 | 76 | 77 | 78 | 79 | 80 | ); 81 | } 82 | -------------------------------------------------------------------------------- /aula 3/frontend/src/components/Chat.tsx: -------------------------------------------------------------------------------- 1 | import { SocketContext } from '@/contexts/SocketContext'; 2 | import Image from 'next/image'; 3 | import { FormEvent, useContext, useEffect, useRef, useState } from 'react'; 4 | interface IChatMessage { 5 | message: string; 6 | username: string; 7 | roomId: string; 8 | time: string; 9 | } 10 | export default function Chat({ roomId }: { roomId: string }) { 11 | const currentMsg = useRef(null); 12 | const { socket } = useContext(SocketContext); 13 | const [chat, setChat] = useState([]); 14 | useEffect(() => { 15 | socket?.on('chat', (data) => { 16 | console.log('message: ', data); 17 | setChat((prevState) => [...prevState, data]); 18 | }); 19 | }, [socket]); 20 | 21 | function sendMessage(e: FormEvent) { 22 | e.preventDefault(); 23 | console.log(currentMsg.current?.value); 24 | if (currentMsg.current && currentMsg.current?.value !== '') { 25 | const sendMsgToServer = { 26 | message: currentMsg.current.value, 27 | username: 'Alexia Kattah', 28 | roomId, 29 | time: new Date().toLocaleTimeString(), 30 | }; 31 | 32 | socket?.emit('chat', sendMsgToServer); 33 | setChat((prevState) => [...prevState, sendMsgToServer]); 34 | 35 | currentMsg.current.value = ''; 36 | } 37 | } 38 | return ( 39 |
40 |
41 | {chat.map((chat, index) => { 42 | return ( 43 |
44 |
45 | {chat.username} 46 | {chat.time} 47 |
48 |
49 |

{chat.message}

50 |
51 |
52 | ); 53 | })} 54 | 55 |
sendMessage(e)} 58 | > 59 |
60 | 67 | 76 |
77 |
78 |
79 |
80 | ); 81 | } 82 | -------------------------------------------------------------------------------- /aula 1/frontend/src/Icons/Logo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import type { SVGProps } from "react"; 3 | interface SVGRProps { 4 | title?: string; 5 | titleId?: string; 6 | } 7 | const SvgLogo = ({ 8 | title, 9 | titleId, 10 | ...props 11 | }: SVGProps & SVGRProps) => ( 12 | 19 | {title ? {title} : null} 20 | 24 | 29 | 40 | 46 | 47 | 48 | 52 | 53 | 54 | ); 55 | export default SvgLogo; 56 | -------------------------------------------------------------------------------- /aula 2/frontend/src/Icons/Logo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import type { SVGProps } from "react"; 3 | interface SVGRProps { 4 | title?: string; 5 | titleId?: string; 6 | } 7 | const SvgLogo = ({ 8 | title, 9 | titleId, 10 | ...props 11 | }: SVGProps & SVGRProps) => ( 12 | 19 | {title ? {title} : null} 20 | 24 | 29 | 40 | 46 | 47 | 48 | 52 | 53 | 54 | ); 55 | export default SvgLogo; 56 | -------------------------------------------------------------------------------- /aula 3/frontend/src/Icons/Logo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import type { SVGProps } from "react"; 3 | interface SVGRProps { 4 | title?: string; 5 | titleId?: string; 6 | } 7 | const SvgLogo = ({ 8 | title, 9 | titleId, 10 | ...props 11 | }: SVGProps & SVGRProps) => ( 12 | 19 | {title ? {title} : null} 20 | 24 | 29 | 40 | 46 | 47 | 48 | 52 | 53 | 54 | ); 55 | export default SvgLogo; 56 | -------------------------------------------------------------------------------- /aula 3/frontend/src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { 3 | Camera, 4 | Computer, 5 | Mic, 6 | NoCamera, 7 | NoComputer, 8 | NoMic, 9 | Phone, 10 | } from '@/Icons'; 11 | import { MutableRefObject, useContext, useState } from 'react'; 12 | import Container from './Container'; 13 | import { SocketContext } from '@/contexts/SocketContext'; 14 | 15 | export default function Footer({ 16 | videoMediaStream, 17 | peerConnections, 18 | localStream, 19 | logout, 20 | }: { 21 | videoMediaStream: MediaStream; 22 | peerConnections: MutableRefObject>; 23 | localStream: MutableRefObject; 24 | logout: () => void; 25 | }) { 26 | const [isMuted, setIsMuted] = useState(false); 27 | const [isCameraOff, setIsCameraOff] = useState(false); 28 | const [isScreenSharing, setIsScreenSharing] = useState(false); 29 | const date = new Date(); 30 | const hours = date.getHours().toString().padStart(2, '0') + ':'; 31 | const minutes = date.getMinutes().toString().padStart(2, '0'); 32 | 33 | const toggleMuted = () => { 34 | videoMediaStream?.getAudioTracks().forEach((track) => { 35 | track.enabled = !isMuted; 36 | }); 37 | setIsMuted(!isMuted); 38 | 39 | Object.values(peerConnections.current).forEach((peerConnection) => { 40 | peerConnection.getSenders().forEach((sender) => { 41 | if (sender.track?.kind === 'audio') { 42 | if (videoMediaStream?.getAudioTracks().length > 0) { 43 | sender.replaceTrack( 44 | videoMediaStream 45 | ?.getAudioTracks() 46 | .find((track) => track.kind === 'audio') || null, 47 | ); 48 | } 49 | } 50 | }); 51 | }); 52 | }; 53 | 54 | const toggleVideo = () => { 55 | setIsCameraOff(!isCameraOff); 56 | videoMediaStream?.getVideoTracks().forEach((track) => { 57 | track.enabled = isCameraOff; 58 | }); 59 | 60 | Object.values(peerConnections.current).forEach((peerConnection) => { 61 | peerConnection.getSenders().forEach((sender) => { 62 | if (sender.track?.kind === 'video') { 63 | sender.replaceTrack( 64 | videoMediaStream 65 | ?.getVideoTracks() 66 | .find((track) => track.kind === 'video') || null, 67 | ); 68 | } 69 | }); 70 | }); 71 | }; 72 | 73 | const toggleScreenSharing = async () => { 74 | if (!isScreenSharing) { 75 | const videoShareScreen = await navigator.mediaDevices.getDisplayMedia({ 76 | video: true, 77 | }); 78 | if (localStream.current) localStream.current.srcObject = videoShareScreen; 79 | 80 | Object.values(peerConnections.current).forEach((peerConnections) => { 81 | peerConnections.getSenders().forEach((sender) => { 82 | if (sender.track?.kind === 'video') { 83 | sender.replaceTrack(videoShareScreen.getVideoTracks()[0]); 84 | } 85 | }); 86 | }); 87 | 88 | setIsScreenSharing(!isScreenSharing); 89 | return; 90 | } 91 | 92 | if (localStream.current) localStream.current.srcObject = videoMediaStream; 93 | 94 | Object.values(peerConnections.current).forEach((peerConnections) => { 95 | peerConnections.getSenders().forEach((sender) => { 96 | if (sender.track?.kind === 'video') { 97 | sender.replaceTrack(videoMediaStream?.getVideoTracks()[0]); 98 | } 99 | }); 100 | }); 101 | setIsScreenSharing(!isScreenSharing); 102 | }; 103 | 104 | return ( 105 |
106 | 107 |
108 |
109 |

110 | {hours} 111 | {minutes} 112 |

113 |
114 |
115 | {isMuted ? ( 116 | toggleMuted()} 119 | /> 120 | ) : ( 121 | toggleMuted()} 124 | /> 125 | )} 126 | {isCameraOff ? ( 127 | toggleVideo()} 130 | /> 131 | ) : ( 132 | toggleVideo()} 135 | /> 136 | )} 137 | 138 | {isScreenSharing ? ( 139 | toggleScreenSharing()} 142 | /> 143 | ) : ( 144 | toggleScreenSharing()} 147 | /> 148 | )} 149 | 150 | 154 |
155 |
156 |
157 |
158 | ); 159 | } 160 | -------------------------------------------------------------------------------- /aula 1/frontend/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /aula 2/frontend/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /aula 3/frontend/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /aula 3/frontend/src/app/room/[id]/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import Chat from '@/components/Chat'; 3 | import Footer from '@/components/Footer'; 4 | import Header from '@/components/Header'; 5 | import { SocketContext } from '@/contexts/SocketContext'; 6 | import { useRouter } from 'next/navigation'; 7 | import { useContext, useEffect, useRef, useState } from 'react'; 8 | interface IAnswer { 9 | sender: string; 10 | description: RTCSessionDescriptionInit; 11 | } 12 | interface ICandidate { 13 | sender: string; 14 | candidate: RTCIceCandidate; 15 | } 16 | interface IDataStream { 17 | id: string; 18 | stream: MediaStream; 19 | username: string; 20 | } 21 | export default function Room({ params }: { params: { id: string } }) { 22 | const { socket } = useContext(SocketContext); 23 | const localStream = useRef(null); 24 | const router = useRouter(); 25 | const peerConnections = useRef>({}); 26 | const [remoteStreams, setRemoteStreams] = useState([]); 27 | const [videoMediaStream, setVideoMediaStream] = useState( 28 | null, 29 | ); 30 | 31 | useEffect(() => { 32 | const username = sessionStorage.getItem('username'); 33 | socket?.on('connect', async () => { 34 | console.log('conectado'); 35 | socket?.emit('subscribe', { 36 | roomId: params.id, 37 | socketId: socket.id, 38 | username, 39 | }); 40 | await initLocalCamera(); 41 | }); 42 | 43 | socket?.on('new user', (data) => { 44 | console.log('Novo usuário tentando se conectar', data); 45 | createPeerConnection(data.socketId, false, data.username); 46 | socket.emit('newUserStart', { 47 | to: data.socketId, 48 | sender: socket.id, 49 | username, 50 | }); 51 | }); 52 | 53 | socket?.on('newUserStart', (data) => { 54 | console.log('Usuário conectado na sala', data); 55 | createPeerConnection(data.sender, true, data.username); 56 | }); 57 | socket?.on('sdp', (data) => handleAnswer(data)); 58 | 59 | socket?.on('ice candidates', (data) => handleIceCandidates(data)); 60 | }, [socket]); 61 | 62 | const handleIceCandidates = async (data: ICandidate) => { 63 | const peerConnection = peerConnections.current[data.sender]; 64 | if (data.candidate) { 65 | await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate)); 66 | } 67 | }; 68 | 69 | const handleAnswer = async (data: IAnswer) => { 70 | const peerConnection = peerConnections.current[data.sender]; 71 | if (data.description.type === 'offer') { 72 | await peerConnection.setRemoteDescription(data.description); 73 | 74 | const answer = await peerConnection.createAnswer(); 75 | await peerConnection.setLocalDescription(answer); 76 | console.log('criando uma resposta'); 77 | socket?.emit('sdp', { 78 | to: data.sender, 79 | sender: socket?.id, 80 | description: peerConnection.localDescription, 81 | }); 82 | } else if (data.description.type === 'answer') { 83 | console.log('ouvindo a oferta'); 84 | await peerConnection.setRemoteDescription( 85 | new RTCSessionDescription(data.description), 86 | ); 87 | } 88 | }; 89 | 90 | const createPeerConnection = async ( 91 | socketId: string, 92 | createOffer: boolean, 93 | username: string, 94 | ) => { 95 | const config = { 96 | iceServers: [ 97 | { 98 | urls: 'stun:stun.l.google.com:19302', 99 | }, 100 | ], 101 | }; 102 | 103 | const peer = new RTCPeerConnection(config); 104 | peerConnections.current[socketId] = peer; 105 | const peerConnection = peerConnections.current[socketId]; 106 | 107 | if (videoMediaStream) { 108 | videoMediaStream.getTracks().forEach((track) => { 109 | peerConnection.addTrack(track, videoMediaStream); 110 | }); 111 | } else { 112 | const video = await initRemoteCamera(); 113 | video 114 | .getTracks() 115 | .forEach((track) => peerConnection.addTrack(track, video)); 116 | } 117 | 118 | if (createOffer) { 119 | const peerConnection = peerConnections.current[socketId]; 120 | 121 | const offer = await peerConnection.createOffer(); 122 | await peerConnection.setLocalDescription(offer); 123 | console.log('criando uma oferta'); 124 | socket?.emit('sdp', { 125 | to: socketId, 126 | sender: socket?.id, 127 | description: peerConnection.localDescription, 128 | }); 129 | } 130 | 131 | peerConnection.ontrack = (event) => { 132 | const remoteStream = event.streams[0]; 133 | 134 | const dataStream: IDataStream = { 135 | id: socketId, 136 | stream: remoteStream, 137 | username, 138 | }; 139 | 140 | setRemoteStreams((prevState: IDataStream[]) => { 141 | if (!prevState.some((stream) => stream.id === socketId)) { 142 | return [...prevState, dataStream]; 143 | } 144 | return prevState; 145 | }); 146 | }; 147 | 148 | peer.onicecandidate = (event) => { 149 | if (event.candidate) { 150 | socket?.emit('ice candidates', { 151 | to: socketId, 152 | sender: socket?.id, 153 | candidate: event.candidate, 154 | }); 155 | } 156 | }; 157 | peerConnection.onsignalingstatechange = (event) => { 158 | switch (peerConnection.signalingState) { 159 | case 'closed': 160 | setRemoteStreams((prevState) => 161 | prevState.filter((stream) => stream.id !== socketId), 162 | ); 163 | 164 | break; 165 | } 166 | }; 167 | peerConnection.onconnectionstatechange = (event) => { 168 | switch (peerConnection.connectionState) { 169 | case 'disconnected': 170 | setRemoteStreams((prevState) => 171 | prevState.filter((stream) => stream.id !== socketId), 172 | ); 173 | case 'failed': 174 | setRemoteStreams((prevState) => 175 | prevState.filter((stream) => stream.id !== socketId), 176 | ); 177 | case 'closed': 178 | setRemoteStreams((prevState) => 179 | prevState.filter((stream) => stream.id !== socketId), 180 | ); 181 | break; 182 | } 183 | }; 184 | }; 185 | const logout = () => { 186 | videoMediaStream?.getTracks().forEach((track) => { 187 | track.stop(); 188 | }); 189 | Object.values(peerConnections.current).forEach((peerConnection) => { 190 | peerConnection.close(); 191 | }); 192 | socket?.disconnect(); 193 | router.push('/'); 194 | }; 195 | 196 | const initLocalCamera = async () => { 197 | const video = await navigator.mediaDevices.getUserMedia({ 198 | video: true, 199 | audio: { 200 | echoCancellation: true, 201 | noiseSuppression: true, 202 | }, 203 | }); 204 | setVideoMediaStream(video); 205 | if (localStream.current) localStream.current.srcObject = video; 206 | }; 207 | const initRemoteCamera = async () => { 208 | const video = await navigator.mediaDevices.getUserMedia({ 209 | video: true, 210 | audio: { 211 | echoCancellation: true, 212 | noiseSuppression: true, 213 | }, 214 | }); 215 | return video; 216 | }; 217 | 218 | return ( 219 |
220 |
221 |
222 |
223 |
224 |
225 | 230 | 231 | {sessionStorage.getItem('username')} 232 | 233 |
234 | {remoteStreams.map((stream, index) => { 235 | return ( 236 |
240 |
250 | ); 251 | })} 252 |
253 |
254 | 255 |
256 |
262 |
263 | ); 264 | } 265 | -------------------------------------------------------------------------------- /aula 2/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | "rootDir": "./src", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /aula 3/backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | "rootDir": "./src", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | --------------------------------------------------------------------------------