Building a Simple Video Call Application with React, Go, using WebRTC

Building a Simple Video Call Application with React, Go, using WebRTC

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

  • Basic knowledge of React, TypeScript, and Go
  • Node.js and npm installed
  • Go installed
  • A modern web browser

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

  1. Build the React App:

npm run build        

  1. Run the Go Server:

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


要查看或添加评论,请登录

Michael Putong的更多文章

社区洞察

其他会员也浏览了