当前位置: 首页 > news >正文

Ubuntu 24.04 安装开源WebRTC信令服务器

Ubuntu 24.04 安装开源WebRTC信令服务器

前言

本指南提供了在Ubuntu 24.04环境下安装和配置三种流行的开源WebRTC信令服务器的详细步骤:

  1. Janus - 功能丰富的通用WebRTC服务器
  2. MediaSoup - 高性能的WebRTC选择性转发单元(SFU)
  3. Simple-Peer-Server - 轻量级WebSocket信令服务器

1. 系统准备

更新系统包

sudo apt update
sudo apt upgrade -y

安装通用依赖

sudo apt install -y build-essential git curl wget gnupg2 dirmngr

2. 安装Node.js(用于MediaSoup和Simple-Peer-Server)

# 添加Node.js源
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -# 安装Node.js
sudo apt install -y nodejs# 验证安装
node -v
npm -v

3. 安装Janus Gateway

安装依赖

sudo apt install -y libmicrohttpd-dev libjansson-dev \libssl-dev libsrtp-dev libsofia-sip-ua-dev libglib2.0-dev \libopus-dev libogg-dev libcurl4-openssl-dev liblua5.3-dev \libconfig-dev pkg-config gengetopt libtool automake libnice-dev

下载并编译Janus

# 克隆代码
cd ~
git clone https://github.com/meetecho/janus-gateway.git
cd janus-gatewaygit checkout v1.0.7  # 使用稳定版本# 编译安装
./autogen.sh
./configure --prefix=/opt/janus
make -j$(nproc)
sudo make install
sudo make configs

配置Janus

# 编辑配置文件
sudo nano /opt/janus/etc/janus/janus.jcfg# 在nat_1_1_mapping字段添加服务器公网IP(如果是云服务器)
# nat_1_1_mapping = "your_server_public_ip"# 启用HTTPS(可选但推荐)
sudo nano /opt/janus/etc/janus/janus.transport.http.jcfg
# 将secure = false 改为 secure = true
# 配置cert_pem和key_pem指向SSL证书文件

创建系统服务

sudo nano /etc/systemd/system/janus.service

添加以下内容:

[Unit]
Description=Janus WebRTC Server
After=network.target[Service]
ExecStart=/opt/janus/bin/janus
Restart=on-failure
RestartSec=5
User=root[Install]
WantedBy=multi-user.target

启用并启动服务:

sudo systemctl daemon-reload
sudo systemctl enable janus
sudo systemctl start janus

4. 安装MediaSoup

创建项目目录

mkdir -p ~/mediasoup-server
cd ~/mediasoup-server

初始化项目

npm init -y

安装MediaSoup及依赖

npm install mediasoup mediasoup-client express socket.io

创建基本服务器文件

创建server.js文件:

nano server.js

添加以下内容:

const express = require('express');
const https = require('https');
const fs = require('fs');
const { Server } = require('socket.io');
const mediasoup = require('mediasoup');const app = express();// 静态文件服务
app.use(express.static('public'));// HTTPS服务器配置
const options = {key: fs.readFileSync('/path/to/your/key.pem'),cert: fs.readFileSync('/path/to/your/cert.pem')
};const httpsServer = https.createServer(options, app);
const io = new Server(httpsServer);// 房间管理
const rooms = new Map();// MediaSoup配置
const mediaCodecs = [{kind: 'audio',mimeType: 'audio/opus',clockRate: 48000,channels: 2},{kind: 'video',mimeType: 'video/VP8',clockRate: 90000}
];io.on('connection', async (socket) => {console.log('新客户端连接:', socket.id);// 房间创建或加入socket.on('createRoom', async (callback) => {try {const router = await mediasoup.createRouter({ mediaCodecs });const roomId = Math.random().toString(36).substring(2, 15);rooms.set(roomId, {router,peers: new Map()});callback({ roomId });} catch (error) {console.error('创建房间失败:', error);callback({ error: error.message });}});socket.on('joinRoom', async ({ roomId }, callback) => {try {const room = rooms.get(roomId);if (!room) {return callback({ error: '房间不存在' });}socket.join(roomId);callback({ success: true });} catch (error) {console.error('加入房间失败:', error);callback({ error: error.message });}});// WebRTC信令处理socket.on('getRtpCapabilities', ({ roomId }, callback) => {const room = rooms.get(roomId);if (!room) return callback({ error: '房间不存在' });callback({ rtpCapabilities: room.router.rtpCapabilities });});socket.on('createWebRtcTransport', async ({ roomId }, callback) => {try {const room = rooms.get(roomId);if (!room) return callback({ error: '房间不存在' });const transport = await room.router.createWebRtcTransport({listenIps: [{ip: '0.0.0.0',announcedIp: process.env.ANNOUNCED_IP || '127.0.0.1'}],enableUdp: true,enableTcp: true,preferUdp: true});callback({id: transport.id,iceParameters: transport.iceParameters,iceCandidates: transport.iceCandidates,dtlsParameters: transport.dtlsParameters});room.peers.set(socket.id, { transport });} catch (error) {console.error('创建WebRTC传输失败:', error);callback({ error: error.message });}});// 断开连接socket.on('disconnect', () => {console.log('客户端断开连接:', socket.id);// 清理资源});
});// 启动服务器
const PORT = process.env.PORT || 3000;
httpsServer.listen(PORT, () => {console.log(`MediaSoup服务器运行在 https://localhost:${PORT}`);
});

创建启动脚本

nano start.sh

添加以下内容:

#!/bin/bash# 设置环境变量
export ANNOUNCED_IP=127.0.0.1  # 替换为你的服务器IP# 启动服务器
node server.js

设置执行权限:

chmod +x start.sh

5. 安装Simple-Peer-Server(轻量级信令服务器)

创建项目目录

mkdir -p ~/simple-peer-server
cd ~/simple-peer-server

初始化项目

npm init -y

安装依赖

npm install ws uuid

创建服务器文件

nano server.js

添加以下内容:

const WebSocket = require('ws');
const { v4: uuidv4 } = require('uuid');
const https = require('https');
const fs = require('fs');// 房间管理
const rooms = new Map();// HTTPS配置
const options = {key: fs.readFileSync('/path/to/your/key.pem'),cert: fs.readFileSync('/path/to/your/cert.pem')
};// 创建HTTPS服务器
const server = https.createServer(options);
const wss = new WebSocket.Server({ server });// WebSocket连接处理
wss.on('connection', (ws, req) => {// 为每个连接生成唯一IDconst userId = uuidv4();console.log(`新用户连接: ${userId}`);// 存储用户信息ws.userId = userId;ws.roomId = null;// 消息处理ws.on('message', (message) => {try {const data = JSON.parse(message);switch (data.type) {case 'join_room':handleJoinRoom(ws, data.roomId, data.userName);break;case 'offer':case 'answer':case 'ice_candidate':// 转发WebRTC信令forwardSignaling(ws, data);break;case 'leave_room':handleLeaveRoom(ws);break;default:console.log(`未知消息类型: ${data.type}`);}} catch (error) {console.error('消息处理错误:', error);}});// 断开连接处理ws.on('close', () => {handleDisconnect(ws);});// 错误处理ws.on('error', (error) => {console.error(`WebSocket错误 (${userId}):`, error);});
});// 处理加入房间
function handleJoinRoom(ws, roomId, userName) {// 离开当前房间(如果在其他房间中)if (ws.roomId) {handleLeaveRoom(ws);}// 加入新房间if (!rooms.has(roomId)) {rooms.set(roomId, new Map());}const room = rooms.get(roomId);room.set(ws.userId, {ws,userName: userName || `用户${ws.userId.substring(0, 8)}`});ws.roomId = roomId;// 通知房间内其他用户const userList = [];room.forEach((user, id) => {if (id !== ws.userId) {userList.push({ id, userName: user.userName });// 通知其他用户新用户加入user.ws.send(JSON.stringify({type: 'user_joined',user_id: ws.userId,nickname: userName || `用户${ws.userId.substring(0, 8)}`}));}});// 发送房间内用户列表给新用户ws.send(JSON.stringify({type: 'room_joined',room_id: roomId,users: userList,user_id: ws.userId}));console.log(`${userName || `用户${ws.userId.substring(0, 8)}`} 加入房间 ${roomId}`);
}// 处理离开房间
function handleLeaveRoom(ws) {if (!ws.roomId) return;const room = rooms.get(ws.roomId);if (!room) return;const user = room.get(ws.userId);room.delete(ws.userId);// 如果房间为空,删除房间if (room.size === 0) {rooms.delete(ws.roomId);} else {// 通知其他用户room.forEach((u) => {u.ws.send(JSON.stringify({type: 'user_left',user_id: ws.userId,nickname: user ? user.userName : `用户${ws.userId.substring(0, 8)}`}));});}console.log(`${user ? user.userName : `用户${ws.userId.substring(0, 8)}`} 离开房间 ${ws.roomId}`);ws.roomId = null;
}// 处理断开连接
function handleDisconnect(ws) {console.log(`用户断开连接: ${ws.userId}`);handleLeaveRoom(ws);
}// 转发WebRTC信令
function forwardSignaling(ws, data) {if (!ws.roomId) {ws.send(JSON.stringify({type: 'error',message: '必须先加入房间'}));return;}const room = rooms.get(ws.roomId);if (!room) return;// 添加发送者信息data.sender_id = ws.userId;data.from_user_id = ws.userId;data.sender_name = room.get(ws.userId)?.userName || `用户${ws.userId.substring(0, 8)}`;data.from_user_name = data.sender_name;// 支持两种目标用户ID字段名const targetUserId = data.target_user_id || data.recipient_id;if (!targetUserId) {ws.send(JSON.stringify({type: 'error',message: '缺少目标用户ID'}));return;}const targetUser = room.get(targetUserId);if (!targetUser) {ws.send(JSON.stringify({type: 'error',message: '目标用户不在房间中'}));return;}// 转发消息给目标用户targetUser.ws.send(JSON.stringify(data));
}// 启动服务器
const PORT = process.env.PORT || 8443;
server.listen(PORT, () => {console.log(`信令服务器运行在 https://0.0.0.0:${PORT}`);
});

创建启动脚本

nano start.sh

添加以下内容:

#!/bin/bash# 启动服务器
node server.js

设置执行权限:

chmod +x start.sh

6. 与当前项目集成

修改前端连接配置

修改/home/lhz/meeting/static/js/app.js中的WebSocket连接URL:

// 替换initWebSocket函数中的连接URL
function initWebSocket() {// 使用Simple-Peer-Serverconst wsUrl = 'wss://your-server-ip:8443';// 或使用Janus// const wsUrl = 'wss://your-server-ip:8188';state.socket = new WebSocket(wsUrl);// 其余代码保持不变...
}

配置ICE服务器

确保ICE_SERVERS配置在server.py和前端代码中一致:

# 在server.py中
ICE_SERVERS = [RTCIceServer(urls='stun:stun.l.google.com:19302'),RTCIceServer(urls='stun:stun1.l.google.com:19302'),# 添加自己的TURN服务器配置RTCIceServer(urls='turn:your-turn-server.com:443?transport=tcp',username='your-username',credential='your-credential')
]

7. 生成SSL证书

对于HTTPS/WSS连接,需要SSL证书:

# 生成自签名证书(开发环境)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes# 将证书复制到需要的位置
mkdir -p ~/ssl
cp key.pem cert.pem ~/ssl/

8. 防火墙配置

# 开放必要的端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3478/udp  # STUN/TURN端口
sudo ufw allow 49152:65535/udp  # WebRTC媒体端口范围
sudo ufw reload

9. 监控和日志

Janus日志

# 查看Janus日志
sudo journalctl -u janus -f

MediaSoup/Simple-Peer-Server日志

可以使用pm2来管理Node.js进程并查看日志:

# 安装pm2
sudo npm install -g pm2# 启动服务并设置开机自启
cd ~/simple-peer-server
pm2 start server.js --name signaling-server
pm2 startup
pm2 save# 查看日志
pm2 logs signaling-server

10. 性能优化建议

  1. 调整服务器资源限制

    sudo nano /etc/security/limits.conf
    # 添加以下行
    * soft nofile 65535
    * hard nofile 65535
    
  2. 优化内核参数

    sudo nano /etc/sysctl.conf
    # 添加以下行
    net.core.rmem_max = 16777216
    net.core.wmem_max = 16777216
    net.ipv4.tcp_rmem = 4096 87380 16777216
    net.ipv4.tcp_wmem = 4096 65536 16777216
    net.ipv4.tcp_no_metrics_save = 1
    net.ipv4.tcp_window_scaling = 1
    net.ipv4.tcp_timestamps = 1
    net.ipv4.tcp_sack = 1
    net.core.netdev_max_backlog = 5000
    

    应用配置:

    sudo sysctl -p
    

11. 推荐方案总结

  1. 轻量级部署:选择 Simple-Peer-Server

    • 优点:简单易配置,资源占用少,与当前项目架构相似
    • 适用:小型会议系统,开发环境
  2. 中等规模部署:选择 Janus

    • 优点:功能全面,文档完善,社区活跃
    • 适用:中小规模生产环境,需要多种WebRTC功能
  3. 大规模高并发:选择 MediaSoup

    • 优点:高性能,可扩展性好,支持大规模并发
    • 适用:大规模生产环境,需要处理大量并发连接

根据您的实际需求和服务器资源选择合适的方案。

http://www.dtcms.com/a/602358.html

相关文章:

  • 滨州做微商城网站手机网站源码最好
  • 各态历经性-随机过程
  • 企业网站建设推广方案怎么写西双版纳网站建设
  • 企业微信消息推送系统设计:基于ES(事件溯源思想)解耦规则与任务架构
  • 基于 ESP32 与机器学习的智能语音家居控制系统
  • Ken的Java学习之路——Java中关于面向对象
  • 建设行业协会网站发展的建议crm客户管理系统模板
  • 做电子外贸网站免费vps
  • Java并发编程【JUC】【一】
  • 网站建设需要多久才能学会a963室内设计网
  • 做个手机网站多少钱怎样做网站标题优化
  • kubernetes(k8s)-Service
  • 深度学习基础知识总结(一):深入理解卷积(Convolution)
  • 宁波企业网站搭建特点wordpress 图片等比例缩放
  • 深圳电商网络网站建设什么样的网站可以做站内站
  • 网站建设怎样创建链接手机怎么在百度做网站
  • 麒麟aarch64架构离线部署python相关项目
  • 网站实例网站头部导航样式
  • 本地缓存:多线程问题。volatile
  • 龙岗中心城有学网站建设晋城商城网站开发设计
  • 工业总线协议(Modbus RTU/TCP、PROFINET、EtherCAT)的帧结构、通信速率与实时性对比
  • 平谷青岛网站建设办公空间设计定位
  • 如何建设网站兴田德润可信赖自我介绍ppt配图
  • Oracle ADG 配置闪回导致报表查询延时!
  • 网站建设 好的公司吴江建设工程招标中心网站
  • 2025年安徽省科技创新战略与软科学研究专项重大项目申报条件要求流程
  • asp网站建设流程旅店网站建设规划书
  • uniapp 鸿蒙元服务 真机调试流程指南
  • 网站建设内存seo诊断工具网站
  • NeurIPS 2025 中科大等提出PIR:实例感知后处理修正框架,显著提升时序预测可靠性!