简单的端到端音视频

index.html

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>WebRTC 通话</title>
</head>
<body>
    <button id="startCall">发起通话</button>
    <button id="endCall" disabled>挂断通话</button>
    <video id="localVideo" autoplay muted></video>
    <video id="remoteVideo" autoplay></video>

    <script>
        let localStream;
        let peerConnection;
        const signalingServer = new WebSocket('ws://localhost:8080/ws');

        // 获取本地媒体流
        async function getMedia() {
            try {
                localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
                document.getElementById('localVideo').srcObject = localStream;
            } catch (err) {
                console.error('获取媒体设备失败:', err);
            }
        }

        // 初始化 PeerConnection
        function createPeerConnection() {
            const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
            peerConnection = new RTCPeerConnection(config);

            // 添加本地流
            localStream.getTracks().forEach(track => {
                peerConnection.addTrack(track, localStream);
            });

            // 处理 ICE 候选
            peerConnection.onicecandidate = (event) => {
                if (event.candidate) {
                    signalingServer.send(JSON.stringify({ type: 'candidate', candidate: event.candidate }));
                }
            };

            // 处理远程流
            peerConnection.ontrack = (event) => {
                document.getElementById('remoteVideo').srcObject = event.streams[0];
            };
        }

        // 发起通话按钮
        document.getElementById('startCall').addEventListener('click', async () => {
            const offer = await peerConnection.createOffer();
            await peerConnection.setLocalDescription(offer);
            signalingServer.send(JSON.stringify({ type: 'offer', offer }));
            document.getElementById('startCall').disabled = true;
            document.getElementById('endCall').disabled = false;
        });

        // 挂断按钮
        document.getElementById('endCall').addEventListener('click', () => {
            peerConnection.close();
            peerConnection = null;
            document.getElementById('startCall').disabled = false;
            document.getElementById('endCall').disabled = true;
            document.getElementById('remoteVideo').srcObject = null;
        });

        // 处理信令消息
        signalingServer.onmessage = async (event) => {
            const message = JSON.parse(event.data);
            if (!peerConnection) createPeerConnection();

            switch (message.type) {
                case 'offer':
                    await peerConnection.setRemoteDescription(message.offer);
                    const answer = await peerConnection.createAnswer();
                    await peerConnection.setLocalDescription(answer);
                    signalingServer.send(JSON.stringify({ type: 'answer', answer }));
                    break;
                case 'answer':
                    await peerConnection.setRemoteDescription(message.answer);
                    break;
                case 'candidate':
                    await peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
                    break;
            }
        };
        async function start() {
            await getMedia();
            createPeerConnection();
        }
        start();
    </script>
</body>
</html>

main.go

// server.go
package main

import (
    "github.com/gorilla/websocket"
    "log"
    "net/http"
)

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool { return true },
}

type Client struct {
    conn *websocket.Conn
    send chan []byte
}

var clients = make(map[*Client]bool)
var broadcast = make(chan []byte)

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("WebSocket upgrade error:", err)
        return
    }
    defer conn.Close()

    client := &Client{conn: conn, send: make(chan []byte, 256)}
    clients[client] = true

    // 读取消息并广播给其他客户端
    for {
        _, message, err := conn.ReadMessage()
        if err != nil {
            log.Println("Read error:", err)
            delete(clients, client)
            break
        }
        // 将消息广播给所有其他客户端
        for otherClient := range clients {
            if otherClient != client {
                otherClient.conn.WriteMessage(websocket.TextMessage, message)
            }
        }
    }
}

func main() {
    http.HandleFunc("/ws", handleWebSocket)
    log.Println("信令服务器运行在 :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容