音视频聊天
音视频聊天
浏览器想调用麦克风和摄像头,需要使用https,就算用iframe都不行,可以通过设置浏览器 实验室功能 【能解决问题,但是不是合理的方案】
1. peerjs
WEBRTC 的第三方库,简化使用WEBRTC
peer.on(event, callback);
peer.on('open', function(id) { ... }); //打开事件
peer.on('connection', function(dataConnection) { ... });//连接事件
peer.on('call', function(mediaConnection) { ... }); //呼叫事件
peer.on('data', function(data) { ... }); //传输消息事件
peer.on('close', function() { ... }); //关闭事件
peer.on('disconnected', function() { ... });//断开连接事件
peer.on('error', function(err) { ... }); //错误事件
参考:https://duxinggj.com/www/pc/dxwd/peer/
介绍了turn服务的搭建
搭建trun服务
推荐部署一个 coturn 服务自己用
服务器centos 7.3
yum install git
yum install openssl openssl-devel libevent libevent-devel
git clone https://gitee.com/genge2/coturn?_from=gitee_search
cd coturn
./configure
make
make install
cd /usr/local/etc
cp turnserver.conf.default turnserver.conf
创建用户
turnadmin -a -u admin -p kiss1001 -r duxinggj.com
创建证书 一路回车就好
openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 -nodes
修改/usr/local/etc/turnserver.conf 配置
listening-ip=127.31.25.57 #内网ip
listening-port=3478#默认3478
tls-listening-port=5349#默认5349
relay-ip=127.31.25.57 #内网ip
external-ip=120.111.104.210 #外网ip
lt-cred-mech
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
pidfile=“/var/run/turnserver.pid”
min-port=49152
max-port=65535
user=admin:kiss1001 #创建的用户名和密码
realm=duxinggj.com #一般与turnadmin创建用户时指定的realm一致
cli-password=kiss1001
启动项目
turnserver -o -a -f -v -r duxinggj.com
这个可以看日志
turnserver --min-port 40000 --max-port 60000 -L 0.0.0.0 -a -u admin:kiss1001 -v -f -r nort.gov
校验配置是否成功了
- 有外网的ip就代表成功了
降噪
使用第三方降噪库,如 RNNoise 和 SpeexDSP。
<script src="/rnnoise-wasm/rnnoise-runtime.js"></script>
async function applyRNNoise(stream) {
try {
const audioContext = new AudioContext({ sampleRate: 44100 });
// 创建音频源节点
const sourceNode = audioContext.createMediaStreamSource(stream);
// 注册并创建 RNNoiseNode
await RNNoiseNode.register(audioContext);
const rnNoiseNode = new RNNoiseNode(audioContext);
// 创建 MediaStreamDestinationNode
const outputStream = audioContext.createMediaStreamDestination();
// 创建一个静音的 GainNode
const gainNode = audioContext.createGain();
gainNode.gain.value = 0;
// 将处理链连接:源 -> 降噪 -> 输出流
sourceNode.connect(rnNoiseNode);
rnNoiseNode.connect(outputStream);
// 连接到静音节点,避免浏览器优化问题
rnNoiseNode.connect(gainNode);
gainNode.connect(audioContext.destination);
// 返回处理后的音频流
return outputStream.stream;
} catch (error) {
console.error("Error applying RNNoise:", error);
throw error;
}
}
拓展
const peer = new window.Peer(userName, {
host: "duxinggj.com",
port: 8089,
path: "/dxPeer",
config: {
iceServers: [
{ urls: "stun:119.23.104.210:5349" }, // 自定义 STUN 服务器
{
urls: "turn:119.23.104.210:3478", // 自定义 TURN 服务器
username: "admin",
credential: "kiss1001",
},
],
sdpSemantics: "unified-plan", // 支持统一的 SDP 语义
},
});
new Peer() 的时候,支持指定自定义参数,替换peerId,这里可以使用【用户名】 以实现拨号功能
2. coturn STUN 和 TURN、TLS 介绍 【没有整理】
🎯 一句话总结
WebRTC 的通信三件套是:STUN、TURN、TLS。 它们的关系是:“打洞失败用中继,中继要加密”。
STUN 仅仅是帮助打洞,大多数 NAT 情况下打洞都会失败。
TURN 是 WebRTC 视频通信的 关键 fallback 通道,尤其在移动网络 / 企业网络 / 对称 NAT 场景中。
| 名称 | 全称 | 作用 | 是否中继数据 | 适用场景 |
|---|---|---|---|---|
| STUN | Session Traversal Utilities for NAT | 帮助客户端获取它的公网 IP | ❌ 不转发媒体流 | 双方都能打洞时(NAT 穿透成功) |
| TURN | Traversal Using Relays around NAT | 当打洞失败时,通过中继转发音视频流 | ✅ 是中继服务器 | 打洞失败、对称 NAT、移动网络 |
非常好,这个问题必须搞清楚。WebRTC 实现点对点连接(比如视频/语音)的关键,是它如何让两个设备即使在不同网络中也能“找到彼此”并建立连接。而这背后依赖的就是:
✅ STUN 和 TURN 是什么?有什么区别?
🔷 STUN 详细说明(仅用于“打洞”)
- 当你访问
stun:stun.l.google.com:19302这样的服务器, - 它会告诉你:“你在我这看到的 IP 是 117.x.x.x,端口是 54678”。
- 你的浏览器就知道了自己的公网地址,用于发给对方建立连接。
优点:
- 快速、免费
- 不中转数据,效率高
缺点:
- 仅用于“告诉自己外网 IP”,不负责传输
- 如果 NAT 类型复杂(如对称 NAT)或防火墙严格,无法建立连接
举例说明:
假如:
- 你用移动 4G
- 对方用电信宽带
你们都用 STUN,得到各自的公网 IP,但:
- 一方用了对称 NAT,UDP 端口映射不稳定
- 你发出的 UDP 数据包被对方 NAT 拒绝
结论:连接失败!
🔶 TURN 详细说明(用于中继传输)
- TURN 是“中继服务器”
- 就像一个“邮局”,当双方互相无法直连时,把数据交给 TURN 服务器代传
- 所以,它实际会传输音视频流
TURN 工作原理:
- A、B 都和 TURN 建立连接
- TURN 为 A、B 分别分配 relay 地址
- A → TURN ← B 实现双向通信
优点:
- 能解决 打洞失败、对称 NAT、企业防火墙 等所有情况
- 是 WebRTC 的终极 fallback 方案
缺点:
- 带宽和服务器压力大
- 要求服务器必须稳定、可控
- 最好使用 TLS(turns:) 支持 HTTPS 环境访问
✅ 所以,什么时候用哪个?
| 场景 | 推荐使用 |
|---|---|
| 局域网、简单 NAT | STUN 就足够 |
| 不同运营商网络 | 需要 TURN |
| 手机网络 | 必须用 TURN |
| 小米/华为手机浏览器 | 必须用 TURN(有时还要求 HTTPS + TLS TURN) |
| 企业内网、校园网、防火墙 | 一般 STUN 失败,只能靠 TURN |
✅ 一个标准的 WebRTC 配置(两者都用)
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }, // 优先用 STUN
{
urls: 'turns:yourdomain.com:5349', // STUN 失败时 fallback 用 TURN
username: 'user',
credential: 'pass'
}
]
✅ 总结:
| 项目 | STUN | TURN |
|---|---|---|
| 是否打洞 | ✅ | ❌ |
| 是否中继 | ❌ | ✅ |
| 是否耗服务器流量 | ❌ | ✅(贵) |
| 是否万能 | ❌(50-60% 成功率) | ✅(几乎 100% 成功) |
| 是否适合手机 | ❌ | ✅ |
| 是否支持 TLS | 部分 | ✅(强烈建议) |
如果你想深入,我可以提供一份详细图解版的 STUN 和 TURN 连接流程图,对 NAT 穿透机制也能解释得非常清楚。是否需要?
✅ 一、STUN 是啥?
🔹 作用:告诉浏览器「我自己的公网 IP 和端口」是什么
📦 举个例子:
你在 NAT 路由器后面(比如家里),你不知道你真正的公网 IP 和端口。
这时浏览器问 STUN 服务器:“我公网长啥样?” STUN 返回:“你是 123.123.123.123:54321” 于是你就知道该用哪个地址去打洞(P2P 连接)了。
✅ 轻量级、无状态、不收费 ❌ 不能中转数据,只能打洞!
✅ 二、TURN 是啥?
🔹 作用:如果 P2P 打洞失败,我就中转数据(视频/音频)
📦 举个例子:
- 如果两个浏览器实在连不上(比如都在公司网、防火墙特别严格),就必须使用 TURN。
- TURN 是一个“中继服务器”,会像“转发机”一样把视频流从 A → TURN → B。
✅ 保证连接一定能成功 ❌ 成本高:会吃带宽,尤其是视频!
✅ 三、TLS 是啥?
🔹 作用:让 TURN 的连接是加密的(不能被窃听)
浏览器现在不允许你连接 非加密的 TURN(就是 turn:),你必须使用 turns:(TLS TURN)。
✅ 加密保证隐私、安全 ❌ 如果没配置证书,浏览器会拒绝连接 turns: 端口!
🧩 它们的关系图:
┌───────┐ ┌────────┐ ┌────────┐
│你浏览器│ ─────▶ │ STUN服务器 │ ─────▶ 获取公网IP:端口
└───────┘ └────────┘
(如果打洞失败)
┌───────┐ relay(TLS) ┌────────┐ relay ┌───────┐
│浏览器A│ ─────────────▶ │ TURN服务器 │ ─────────────▶ │浏览器B│
└───────┘ └────────┘ └───────┘
↑TLS证书保护↑
✅ 总结对比表
| 项目 | STUN | TURN | TLS |
|---|---|---|---|
| 用于打洞 | ✅ | ❌ | ❌ |
| 用于中转 | ❌ | ✅ | ❌ |
| 必须加密 | ❌ | ✅(生产中必须 turns:) | ✅ |
| 浏览器支持 | 是 | 是(需 TLS) | 是 |
| 成本(带宽) | 很低 | 高(会中继数据) | 依赖于证书 |
| 是否需要认证 | 否 | 是(用户名+密码) | 是(证书) |
🛠️ coturn 是干啥的?
coturn 是一个服务器软件,它既可以当 STUN,也可以当 TURN(支持 TLS)
你只部署一个 coturn,它同时支持:
stun::作为 STUNturn:(不加密):作为 TURN(开发测试可用)turns:(加密):作为 TLS TURN,用于生产环境 ✅
✅ 生产环境推荐做法
- 使用 coturn 同时启用 STUN + TLS TURN
- 浏览器配置:
iceServers: [
{ urls: 'stun:yourdomain.com:3478' },
{
urls: 'turns:yourdomain.com:5349',
username: 'user',
credential: 'pass'
}
]