WebRTC 连接在本地网络之外不起作用

Posted

技术标签:

【中文标题】WebRTC 连接在本地网络之外不起作用【英文标题】:WebRTC connection not working outside of local network 【发布时间】:2022-01-10 13:57:21 【问题描述】:

我们为 webrtc 双向视频和音频流设置了以下设置:

移动

android 应用程序使用Google WebRTC 实现 java 包装器。测试了这两个库:

implementation 'org.webrtc:google-webrtc:1.0.+'
implementation 'com.github.webrtc-sdk:android:92.4515.03' // https://github.com/webrtc-sdk/android

RPi

带有WebRTC plugin 的Gstreamer 基于gst-examples 并进行了一些修改。

浏览器

还稍微修改了gst-examples javascript 实现。它基于原生浏览器 WebRTC 支持。

在 Docker 中工作的 Coturn 服务器 (coturn/coturn)。

问题

当从 RPi 调用浏览器或手机调用浏览器时,无论是在本地网络还是通过 Internet(通过 TURN 服务器),一切正常。但是,当尝试通过 Internet 连接 RPi 和 Android 设备时,它会卡住(本地网络也可以)。设备相互通信,协商 SDP 和 ICE 候选,TURN 服务器正确打开连接,但没有音频/视频。

查看Android日志时,第一个区别是没有触发ICE连接变化:

PeerConnectionObserver: onStandardizedIceConnectionChange: CHECKING

也没有

PeerConnectionObserver: onConnectionChange: CONNECTING

这发生在 ICE 候选人交换之前。发送 ICE 候选后,不会与其他设备进行进一步通信,也不会触发任何状态更改。例如在工作案例中的这些:

PeerConnectionObserver: onSelectedCandidatePairChanged: org.webrtc.CandidatePairChangeEvent@a856333
PeerConnectionObserver: onStandardizedIceConnectionChange: CONNECTED
PeerConnectionObserver: onConnectionChange: CONNECTED
PeerConnectionObserver: onIceConnectionChange CONNECTED
[Internal data channel]: onStateChange
PeerConnectionObserver: onDataChannel org.webrtc.DataChannel@b76f6f0
[External data channel]: onStateChange

coturn 日志根本没有显示任何可疑之处。

在进一步调查此问题时提供任何提示或帮助。

编辑 在@RSATom 的建议下,我们更仔细地查看了正在发送的 ICE 和 SDP 消息,并没有发现任何差异。对于通过 Internet 和本地的移动 RPi 通信,SDP 是相同的。唯一的区别是随机生成的 id。 ICE 也没有太大区别。第一个发送者(提议者)是相同的,而回答者则略有不同,因为它包含 TURN 详细信息:

通过互联网

video0:0:candidate:228040959 1 udp 2122260223 10.111.215.156 53556 typ host generation 0 ufrag 3SNh network-id 3 network-cost 900::UNKNOWN  
video0:0:candidate:559267639 1 udp 2122202367 ::1 48566 typ host generation 0 ufrag 3SNh network-id 2::UNKNOWN      
video0:0:candidate:1510613869 1 udp 2122129151 127.0.0.1 41279 typ host generation 0 ufrag 3SNh network-id 1::UNKNOWN   
video0:0:candidate:1876313031 1 tcp 1518222591 ::1 46051 typ host tcptype passive generation 0 ufrag 3SNh network-id 2::UNKNOWN 
video0:0:candidate:344579997 1 tcp 1518149375 127.0.0.1 60259 typ host tcptype passive generation 0 ufrag 3SNh network-id 1::UNKNOWN    
video0:0:candidate:842163049 1 udp 1686052607 31.0.91.196 6742 typ srflx raddr 10.111.215.156 rport 53556 generation 0 ufrag 3SNh network-id 3 network-cost 900:stun:3.70.23.20:3478:UNKNOWN    
video0:0:candidate:593469510 1 udp 41885439 172.31.0.169 14307 typ relay raddr 31.0.91.196 rport 6742 generation 0 ufrag 3SNh network-id 3 network-cost 900:turn:3.70.23.20:3478?transport=udp:UNKNOWN

通过本地 WiFi

video0:0:candidate:2858526953 1 udp 2122260223 192.168.0.21 38123 typ host generation 0 ufrag rwx/ network-id 3 network-cost 10::UNKNOWN
video0:0:candidate:559267639 1 udp 2122202367 ::1 52058 typ host generation 0 ufrag rwx/ network-id 2::UNKNOWN
video0:0:candidate:1510613869 1 udp 2122129151 127.0.0.1 39469 typ host generation 0 ufrag rwx/ network-id 1::UNKNOWN
video0:0:candidate:842163049 1 udp 1686052607 178.235.191.135 13607 typ srflx raddr 192.168.0.21 rport 38123 generation 0 ufrag rwx/ network-id 3 network-cost 10:stun:3.70.23.20:3478:UNKNOWN
video0:0:candidate:1876313031 1 tcp 1518222591 ::1 51551 typ host tcptype passive generation 0 ufrag rwx/ network-id 2::UNKNOWN
video0:0:candidate:344579997 1 tcp 1518149375 127.0.0.1 41007 typ host tcptype passive generation 0 ufrag rwx/ network-id 1::UNKNOWN
video0:0:candidate:593469510 1 udp 41885439 172.31.0.169 13744 typ relay raddr 178.235.191.135 rport 13607 generation 0 ufrag rwx/ network-id 3 network-cost 10:turn:3.70.23.20:3478?transport=udp:UNKNOWN

ICE 消息的顺序似乎没有保留。

完整日志的差异(互联网左侧,本地右侧):https://www.diffchecker.com/elEA6rkJ

ICE 消息差异:https://www.diffchecker.com/C1TzPcMm

【问题讨论】:

您使用的是什么 GStreamer 版本?某些版本中存在一些错误... 1.18.5 这似乎是最新版本。但是版本控制是一团糟 你使用“notify::ice-gathering-state”通知吗?如果是,它甚至在 1.18.5 中都已损坏。 我错了notify::ice-gathering-state 已在 1.17.1... 【参考方案1】:

在你的情况下我会怎么做:

    为 create-offer/create-answer/set-offer/set-answer 请求添加日志 为每个传入/传出的 Ice Candidate 和 end-of-candidates 添加日志

然后查看日志并检查:

    所有 Ice 候选者都在真正交付给对方。 end-of-candidates 在所有其他 Ice 候选人之后交付。 在 set-offer/set-answer 之后出现的 Ice 候选人 双方都可以真正访问您的 STUN/TURN 服务器(使用 https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/) 您在 STUN/TURN 服务器上配置了 IPv6(一些 GSM 提供商根本无法使用 IPv4)

更新 1

根据日志,您的 Android 设备具有 IPv4。因此,现在无需担心 IPv6。 关于end-of-candidates - 你可以看看我是如何用webrtcbin here 生成它的。 Android的类似代码:

    private val connectionObserver = object: PeerConnection.Observer 
        // ... some overrides skipped ...

        override fun onIceCandidate(candidate: IceCandidate) 
            Log.d(TAG, "onIceCandidate \"$candidate\"")
        
        override fun onIceGatheringChange(state: PeerConnection.IceGatheringState) 
            Log.d(TAG, "IceGathering state: $state")
            if(state == PeerConnection.IceGatheringState.COMPLETE) 
                Log.d(TAG, "onIceCandidate \"a=end-of-candidates\"")
            
        

        // ... some overrides skipped ...
    

还请检查以下内容:

在安卓上

    对于每一位即将到来的 Ice 候选人,您都可以直接致电 org.webrtc.PeerConnection.addIceCandidate 你在之后 org.webrtc.PeerConnection.setRemoteDescription打电话

在树莓派上

    你真的是打电话给 g_signal_emit_by_nameadd-ice-candidate 为每一位即将到来的 Ice 候选人

更新 2

我注意到您的中继 Ice Candidate 指向专用网络 IP (172.31.0.169)。这可能意味着您的 TURN 服务器配置错误。

【讨论】:

嗨@RSATom,感谢您的回答!我们改进了我们的日志记录(见编辑)并遵循您的清单。一切看起来都还不错,但是……这两种情况都没有end-of-candidates 通信。此外,我们在转向服务器上为 IPv4 和 IPv6 开放了端口,并且 coturn 应该开箱即用地处理 IPv6 流量,但我们不知道如何测试它是否真的被允许。如果您能看看 ICE 候选人并分享您的见解,那就太好了!再次感谢

以上是关于WebRTC 连接在本地网络之外不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用 webrtc 时 ReplayKit 不起作用

(webrtc) setRemoteDescription 对发起者不起作用

已解决:强大在本地主机之外不起作用

WebRTC:忍者构建不起作用

WebRTC - 如何静音本地音频输出

Flutter - webRTC 视频通话信号不起作用