Building a Simple Video Call Application with React, Go, using WebRTC
Michael Putong
Full Stack Engineer | Go | Javascript | Typescript | Node.Js | Python | Stupid-Scientist | Wannabe-Musician | Perpetual-Learner | ex- Dota & Pointblank noob-player
In this tutorial, we'll build a simple video call application using React with TypeScript for the frontend and Go for the backend, leveraging the WebRTC protocol for real-time communication.
Prerequisites
Setting Up the Project
1. Initialize the React Frontend with Vite and TypeScript
First, let's create a new React project using Vite with TypeScript.
npm create vite@latest client --template react-ts
cd client
Install the necessary dependencies:
npm install
npm install simple-peer socket.io-client
2. Set Up the Go Backend
Back to the parent directory for the Go server:
cd ..
Initialize a new Go module:
go mod init github.com/michaelwp/go-meet
We'll use the gorilla/websocket package for handling WebSocket connections:
go get github.com/gorilla/websocket
Implementing the Signaling Server
WebRTC requires a signaling mechanism to exchange connection details (SDP and ICE candidates) between peers. We'll use WebSockets for this purpose.
领英推荐
1. Go Server Implementation
Create a file main.go in the go-server directory:
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Message)
type Message struct {
Type string `json:"type"`
Data string `json:"data"`
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatalf("error upgrading request: %v", err)
}
defer ws.Close()
clients[ws] = true
for {
var msg Message
err := ws.ReadJSON(&msg)
if err != nil {
log.Printf("error reading json: %v", err)
delete(clients, ws)
break
}
broadcast <- msg
}
}
func handleMessages() {
for {
msg := <-broadcast
for client := range clients {
err := client.WriteJSON(msg)
if err != nil {
log.Printf("error writing json: %v", err)
client.Close()
delete(clients, client)
}
}
}
}
func main() {
fs := http.FileServer(http.Dir("./client/dist"))
http.Handle("/", fs)
http.HandleFunc("/ws", handleConnections)
go handleMessages()
log.Println("http server started on :8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatalf("server failed to start: %v", err)
}
}
This Go server handles WebSocket connections and broadcasts messages to all connected clients. The frontend will communicate with this server for signaling.
Implementing the React Frontend with TypeScript
1. Setting Up WebRTC
In src/App.tsx, we'll set up WebRTC using the simple-peer library:
import React, { useEffect, useRef, useState } from "react";
import io, { Socket } from "socket.io-client";
import Peer, { SignalData } from "simple-peer";
const App: React.FC = () => {
const [stream, setStream] = useState<MediaStream | undefined>(undefined);
const [peer, setPeer] = useState<Peer.Instance | undefined>(undefined);
const socket = useRef<Socket | undefined>(undefined);
const userVideo = useRef<HTMLVideoElement>(null);
const partnerVideo = useRef<HTMLVideoElement>(null);
useEffect(() => {
socket.current = io("https://localhost:8080/ws");
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((stream) => {
setStream(stream);
if (userVideo.current) {
userVideo.current.srcObject = stream;
}
});
socket.current.on("signal", (data: SignalData) => {
if (!peer) {
const newPeer = new Peer({ initiator: false, trickle: false, stream: stream! });
newPeer.signal(data);
setPeer(newPeer);
}
});
socket.current.on("connect", () => {
if (!peer) {
const newPeer = new Peer({ initiator: true, trickle: false, stream: stream! });
setPeer(newPeer);
}
});
return () => {
socket.current?.disconnect();
};
}, [peer, stream]);
useEffect(() => {
if (peer) {
peer.on("signal", (data) => {
socket.current?.emit("signal", data);
});
peer.on("stream", (stream) => {
if (partnerVideo.current) {
partnerVideo.current.srcObject = stream;
}
});
}
}, [peer]);
return (
<div>
<video ref={userVideo} autoPlay muted />
<video ref={partnerVideo} autoPlay />
</div>
);
};
export default App;
Running the Application
npm run build
cd ..
go run main.go
Navigate to https://localhost:8080 in two different browser windows or devices to test the video call functionality.
Conclusion
This simple implementation demonstrates the basic setup for a video call application using React, TypeScript, Go, and WebRTC. There are many potential enhancements, such as adding room functionality, user authentication, and handling more complex peer-to-peer scenarios.
Code repository go-meet