基于 WebRTC 的简单视频聊天应用的完整代码实现,包含前端 HTML/JavaScript 和后端 Node.js 信令服务器。

1. 前端代码(HTML + JavaScript)

创建一个 index.html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>WebRTC 视频通话</title>
  <style>
    body { font-family: Arial, sans-serif; }
    #video-container { display: flex; gap: 20px; }
    video { width: 400px; height: 300px; border: 1px solid #ccc; }
    button { padding: 10px; margin: 5px; }
  </style>
</head>
<body>
  <h1>WebRTC 视频通话</h1>
  <div id="video-container">
    <video id="local-video" autoplay muted></video>
    <video id="remote-video" autoplay></video>
  </div>
  <button id="start-btn">开启摄像头</button>
  <button id="call-btn" disabled>发起通话</button>
  <button id="hangup-btn" disabled>挂断</button>

  <script>
    // 获取DOM元素
    const localVideo = document.getElementById('local-video');
    const remoteVideo = document.getElementById('remote-video');
    const startBtn = document.getElementById('start-btn');
    const callBtn = document.getElementById('call-btn');
    const hangupBtn = document.getElementById('hangup-btn');

    // 全局变量
    let localStream;
    let peerConnection;
    const socket = new WebSocket('ws://localhost:3000'); // 连接到信令服务器

    // 1. 开启摄像头
    startBtn.onclick = async () => {
      try {
        localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
        localVideo.srcObject = localStream;
        startBtn.disabled = true;
        callBtn.disabled = false;
      } catch (err) {
        console.error("获取媒体设备失败:", err);
      }
    };

    // 2. 创建RTCPeerConnection并设置ICE候选
    function createPeerConnection() {
      const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
      peerConnection = new RTCPeerConnection(config);

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

      // 监听远程流
      peerConnection.ontrack = (event) => {
        remoteVideo.srcObject = event.streams[0];
      };

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

    // 3. 发起通话
    callBtn.onclick = async () => {
      createPeerConnection();
      const offer = await peerConnection.createOffer();
      await peerConnection.setLocalDescription(offer);
      socket.send(JSON.stringify({ type: 'offer', offer }));
      hangupBtn.disabled = false;
    };

    // 4. 挂断通话
    hangupBtn.onclick = () => {
      peerConnection.close();
      peerConnection = null;
      remoteVideo.srcObject = null;
      hangupBtn.disabled = true;
      callBtn.disabled = false;
    };

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

      if (message.type === 'offer') {
        await peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        socket.send(JSON.stringify({ type: 'answer', answer }));
      } 
      else if (message.type === 'answer') {
        await peerConnection.setRemoteDescription(new RTCSessionDescription(message.answer));
      } 
      else if (message.type === 'candidate') {
        await peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
      }
    };
  </script>
</body>
</html>

2. 后端信令服务器(Node.js)

创建一个 server.js 文件:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3000 });

let clients = [];

wss.on('connection', (ws) => {
  clients.push(ws);
  console.log(`新用户连接,当前用户数: ${clients.length}`);

  // 转发消息给其他客户端
  ws.on('message', (message) => {
    clients.forEach(client => {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });

  // 清理断开连接的客户端
  ws.on('close', () => {
    clients = clients.filter(client => client !== ws);
    console.log(`用户断开,剩余用户数: ${clients.length}`);
  });
});

console.log('信令服务器运行在 ws://localhost:3000');

3. 如何运行

  1. 启动信令服务器

npm install ws  # 安装WebSocket依赖
node server.js
  1. 打开前端页面

    • 直接双击 index.html 或用 Live Server 打开。

    • 打开两个浏览器窗口(或两个设备),分别点击 开启摄像头 → 发起通话

关键点说明

  1. 信令服务器:负责交换 SDP(Offer/Answer)和 ICE 候选。

  2. STUN 服务器:用于获取公网 IP(Google 的公共 STUN 服务器)。

  3. 媒体流:通过 getUserMedia 获取摄像头和麦克风权限。

  4. RTCPeerConnection:WebRTC 的核心 API,处理连接和流传输。

扩展功能

  • 房间管理:信令服务器可加入房间逻辑(如 Socket.io 房间)。

  • 文字聊天:通过 WebSocket 发送文本消息。

  • 屏幕共享:替换 getUserMedia 为 getDisplayMedia

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@程序员ALMJ

打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值