package.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
{ "name": "agora-video-call", "private": true, "version": "0.0.0", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "dependencies": { "agora-rtc-sdk-ng": "^4.11.1", "react": "^18.0.0", "react-dom": "^18.0.0" }, "devDependencies": { "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@vitejs/plugin-react": "^1.3.0", "vite": "^2.9.9" } } |
App.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { useState } from 'react'; import './App.css'; import { VideoRoom } from './components/VideoRoom'; function App() { const [joined, setJoined] = useState(false); return ( <div className="App"> <h1>WDJ Virtual Call</h1> {!joined && ( <button onClick={() => setJoined(true)}> Join Room </button> )} {joined && <VideoRoom />} </div> ); } export default App; |
Components/VideoPlayer.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React, { useEffect, useRef } from 'react'; export const VideoPlayer = ({ user }) => { const ref = useRef(); useEffect(() => { user.videoTrack.play(ref.current); }, []); return ( <div> Uid: {user.uid} <div ref={ref} style={{ width: '200px', height: '200px' }} ></div> </div> ); }; |
Components/VideoRoom.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
import React, { useEffect, useState } from 'react'; import AgoraRTC from 'agora-rtc-sdk-ng'; import { VideoPlayer } from './VideoPlayer'; const APP_ID = '99ee7677a8a745ed94b7f7f03fdab53e'; const TOKEN = '00699ee7677a8a745ed94b7f7f03fdab53eIAApoyMoTzk7vs7z6VZss24GSras+N37TeYdwlj7EDi9qSKBCQIAAAAAEACKRNzQfi6hYgEAAQCsMKFi'; const CHANNEL = 'wdj'; const client = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp8', }); export const VideoRoom = () => { const [users, setUsers] = useState([]); const [localTracks, setLocalTracks] = useState([]); const handleUserJoined = async (user, mediaType) => { await client.subscribe(user, mediaType); if (mediaType === 'video') { setUsers((previousUsers) => [...previousUsers, user]); } if (mediaType === 'audio') { // user.audioTrack.play() } }; const handleUserLeft = (user) => { setUsers((previousUsers) => previousUsers.filter((u) => u.uid !== user.uid) ); }; useEffect(() => { client.on('user-published', handleUserJoined); client.on('user-left', handleUserLeft); client .join(APP_ID, CHANNEL, TOKEN, null) .then((uid) => Promise.all([ AgoraRTC.createMicrophoneAndCameraTracks(), uid, ]) ) .then(([tracks, uid]) => { const [audioTrack, videoTrack] = tracks; setLocalTracks(tracks); setUsers((previousUsers) => [ ...previousUsers, { uid, videoTrack, audioTrack, }, ]); client.publish(tracks); }); return () => { for (let localTrack of localTracks) { localTrack.stop(); localTrack.close(); } client.off('user-published', handleUserJoined); client.off('user-left', handleUserLeft); client.unpublish(tracks).then(() => client.leave()); }; }, []); return ( <div style={{ display: 'flex', justifyContent: 'center' }} > <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 200px)', }} > {users.map((user) => ( <VideoPlayer key={user.uid} user={user} /> ))} </div> </div> ); }; |
https://github.com/codyseibert/agora-video-call/tree/live