浏览器与Django服务器间RTCPeerConnection连接失败求助
问题分析与解决建议
问题现象
- 服务器可接收浏览器Offer,浏览器能接收服务器Answer,但在部分WiFi、4G移动网络下连接中断,本地及部分WiFi环境连接正常
- 浏览器控制台打印“receive server video”及MediaStream对象,但视频元素无画面显示
- 服务器日志显示连接状态从
connecting变为failed,最终转为closed - 出现
InvalidStateError('invalid state')错误,溯源至aioice库的TurnClientMixin逻辑
服务器端代码
@aioConnection.on("connectionstatechange") async def on_connectionstatechange(): print("Connection state is %s" % aioConnection.connectionState) @aioConnection.on("track") def on_track(track): print("======= received track: ", track, flush=True) if track.kind == "video": newTrack = VideoStreamTrack(track) aioConnection.addTrack(newTrack)
服务器日志
Oct 5 06:00:43 ip-172-31-30-121 gunicorn[2999]: /home/ubuntu/.local/lib/python3.10/site-packages/aiortc/rtcdtlstransport.py:186: CryptographyDeprecationWarning: This version of cryptography contains a temporary pyOpenSSL fallback path. Upgrade pyOpenSSL now. Oct 5 06:00:43 ip-172-31-30-121 gunicorn[2999]: value=certificate_digest(self._cert._x509), # type: ignore Oct 5 06:00:43 ip-172-31-30-121 gunicorn[2999]: ======= received track: <aiortc.rtcrtpreceiver.RemoteStreamTrack object at 0x7efde9842ec0> Oct 5 06:00:43 ip-172-31-30-121 gunicorn[2999]: Connection 1 state is connecting Oct 5 06:01:15 ip-172-31-30-121 gunicorn[2999]: Connection 1 state is failed Oct 5 06:01:15 ip-172-31-30-121 gunicorn[2999]: Connection 1 state is closed
浏览器端代码
aioConnection.addEventListener('track', function (evt) { console.log("receive server video"); console.log(evt.streams[0]) document.getElementById("video").srcObject = evt.streams[0]; });
关键错误日志
Task exception was never retrieved <Task finished name='Task-82' coro=<TurnClientMixin.delete() done, defined at /home/ubuntu/.local/lib/python3.10/site-packages/aioice/turn.py:147> exception=InvalidStateError('invalid state')> Traceback (most recent call last): File "/home/ubuntu/.local/lib/python3.10/site-packages/aioice/turn.py", line 167, in delete self.receiver.connection_lost(None) File "/home/ubuntu/.local/lib/python3.10/site-packages/aioice/ice.py", line 175, in connection_lost self.__closed.set_result(True) asyncio.exceptions.InvalidStateError: invalid state
解决建议
1. 补全STUN/TURN服务器配置
部分网络(如4G、严格NAT的WiFi)无法直接建立P2P连接,必须依赖中转服务器:
- 服务器端和浏览器端均需配置有效的STUN/TURN服务器地址、用户名及密码
- 用trickle-ice工具验证网络能否通过STUN获取公网地址,或通过TURN中转流量
- 强制开启TURN中转,避免依赖不稳定的P2P连接
2. 修复ICE连接异常处理
日志中的InvalidStateError是ICE连接失败后,aioice内部重复标记连接关闭导致的,需从根源解决ICE问题:
- 调整ICE连接超时阈值,避免过早判定连接失败
- 服务器端新增
iceconnectionstatechange事件监听,排查ICE候选是否正常交换 - 确保浏览器端收集并发送所有ICE候选到服务器,服务器端同步推送自身ICE候选给浏览器
3. 修正视频轨道与播放逻辑
浏览器收到MediaStream但无画面,多因轨道未激活或视频元素属性缺失:
- 给视频元素添加必要属性,适配移动端播放:
<video id="video" autoplay playsinline muted></video> - 修复服务器端
on_track函数的缩进错误,确保视频轨道正确初始化并添加:@aioConnection.on("track") def on_track(track): print("======= received track: ", track, flush=True) if track.kind == "video": newTrack = VideoStreamTrack(track) aioConnection.addTrack(newTrack)
4. 升级依赖库解决DTLS警告
服务器日志中的加密库警告可能引发DTLS握手问题,执行以下命令更新依赖:
pip install --upgrade pyopenssl cryptography
5. 排查网络端口与防火墙限制
- 检查服务器防火墙是否开放ICE/RTCP所需端口(UDP 3478、443及动态端口范围)
- 4G网络下需确认运营商未限制RTMP/RTCP流量,必要时切换TURN服务器端口为443
内容的提问来源于stack exchange,提问作者Ikochoy
相关产品推荐
相关产品推荐

