音视频聊天

lishihuan大约 7 分钟

音视频聊天

浏览器想调用麦克风和摄像头,需要使用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/open in new window

介绍了turn服务的搭建open in new window

vue项目带源码open in new window

demoopen in new window

搭建trun服务

推荐部署一个 coturn 服务自己用

https://www.duxinggj.com/www/pc/dxwd/peer/turn.htmlopen in new window

https://zego.csdn.net/636b1117d3efff3090b5f6d7.htmlopen in new window

服务器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

校验配置是否成功了

校验配置(opens new window)open in new window

  1. 有外网的ip就代表成功了

降噪

<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 场景中。

名称全称作用是否中继数据适用场景
STUNSession Traversal Utilities for NAT帮助客户端获取它的公网 IP❌ 不转发媒体流双方都能打洞时(NAT 穿透成功)
TURNTraversal 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 工作原理:

  1. A、B 都和 TURN 建立连接
  2. TURN 为 A、B 分别分配 relay 地址
  3. A → TURN ← B 实现双向通信

优点:

  • 能解决 打洞失败、对称 NAT、企业防火墙 等所有情况
  • 是 WebRTC 的终极 fallback 方案

缺点:

  • 带宽和服务器压力大
  • 要求服务器必须稳定、可控
  • 最好使用 TLS(turns:) 支持 HTTPS 环境访问

✅ 所以,什么时候用哪个?

场景推荐使用
局域网、简单 NATSTUN 就足够
不同运营商网络需要 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'
  }
]

✅ 总结:

项目STUNTURN
是否打洞
是否中继
是否耗服务器流量✅(贵)
是否万能❌(50-60% 成功率)✅(几乎 100% 成功)
是否适合手机
是否支持 TLS部分✅(强烈建议)

如果你想深入,我可以提供一份详细图解版的 STUN 和 TURN 连接流程图open in new window,对 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证书保护↑

✅ 总结对比表

项目STUNTURNTLS
用于打洞
用于中转
必须加密✅(生产中必须 turns:
浏览器支持是(需 TLS)
成本(带宽)很低高(会中继数据)依赖于证书
是否需要认证是(用户名+密码)是(证书)

🛠️ coturn 是干啥的?

coturn 是一个服务器软件,它既可以当 STUN,也可以当 TURN(支持 TLS)

你只部署一个 coturn,它同时支持:

  • stun::作为 STUN
  • turn:(不加密):作为 TURN(开发测试可用)
  • turns:(加密):作为 TLS TURN,用于生产环境 ✅

✅ 生产环境推荐做法

  • 使用 coturn 同时启用 STUN + TLS TURN
  • 浏览器配置:
iceServers: [
  { urls: 'stun:yourdomain.com:3478' },
  {
    urls: 'turns:yourdomain.com:5349',
    username: 'user',
    credential: 'pass'
  }
]

cotrun服务的部署

coturn部署