1

我用这个把头发拉出来。大约一个月前,我能够使用 SignalR 的优秀人员提供的一些示例代码,整理出一个概念验证 WebRTC 演示。该演示位于此处,它的源代码在此处,它完成了它应该做的事情。

但是,当我使用该代码并将其移动到我们的实际应用程序中时,我无法让它工作。当然,必须对代码进行重大更改——不同的后端、不同的框架集和支持代码、支持多个同时连接等等——但核心逻辑非常相似。但我无法让它工作。

我在这里整理了一个示例应用程序来演示该问题:

https://bitbucket.org/smithkl42/signalr.webrtc

核心 WebRTC 逻辑都在这个 TypeScript 文件中:

https://bitbucket.org/smithkl42/signalr.webrtc/src/tip/SignalR.WebRTC/Scripts/Media/WebRTC.ts?at=default

它有几百行长,所以我不会在这里发布它,但是您可以通过单击上面的链接来查看它。

当它运行时,它会产生如下输出:

12:17:58.531 WebRTCController.call(): 准备完成后调用 7d9e0d39-5047-4afe-86e5-e6e01b9f5955

12:17:58.533 WebRTCController.prepareForCall():准备通话:localSessionId='39d2df53-6854-415a-8748-b5230eda2eb1'; remoteSessionId='7d9e0d39-5047-4afe-86e5-e6e01b9f5955'

12:18:0.139 Object.():用户已授予媒体设备访问权限,因此继续准备通话

12:18:0.141 Connection.createPeerConnection():创建对等连接;使用 stunServer stun:stun1.l.google.com:19302

12:18:0.144 ():准备工作完成。创建和发送 JSEP 报价。实用程序.js:21

12:18:0.272 Connection.handleIceCandidate():STUN 服务器找到了一个 ICE 候选者(event.type='icecandidate')。

12:18:0.282 Connection.handleIceCandidate():STUN 服务器找到了一个 ICE 候选者(event.type='icecandidate')。

(更像这样)

12:18:0.655 WebRTCController.handleJsepAnswer():处理来自 7d9e0d39-5047-4afe-86e5-e6e01b9f5955 的 JsepAnswer

12:18:0.694 Object.(): 将 ICE 候选发送到远程机器:{"sdpMLineIndex":0,"sdpMid":"audio","candidate":"a=candidate:2999745851 1 udp 2113937151 192.168.56.1 62978类型主机代 0\r\n"}

12:18:0.706 Object.():向远程机器发送 ICE 候选:{"sdpMLineIndex":0,"sdpMid":"audio","candidate":"a=candidate:2999745851 2 udp 2113937151 192.168.56.1 62978类型主机代 0\r\n"}

(更像这样)

但是它永远不会连接,即来自另一端的视频永远不会开始播放。在信令层,我可以通过日志和单步执行代码来判断第一个浏览器正在发送 JSEP 报价;第二个浏览器正在接收它、存储它并发回一个适当的 JSEP 答案;第一台机器正在存储该答案。然后每个 peerConnection 找到 ICE 候选并将它们发送到远程机器;并且每个 peerConnection 都在接收并显然在尝试那些 ICE 候选人;peerConnections 甚至引发了onaddstream事件。但视频永远不会开始播放。

peerConnection 对象的状态一直如下所示:

(iceGatheringState=new; iceState=starting; readyState=active)

令人沮丧的是,每隔一段时间,也许 20 次中就有一次,它确实有效,即两个视频都会出现。所以我没有做错一切。这听起来像是某种时间问题 - 但我无法弄清楚它是什么。据我所知,WebRTC 对象(特别是 RTCPeerConnection)中没有太多可以告诉您出了什么问题。

我不想让其他人为我进行故障排除,但是......好吧,我已经没有选择了。有没有其他人看到我做错了什么?

2012-12-19 更新:我正在取得一些进展。我意识到我正在peerConnection.setLocalDescription()同步调用,即没有指定回调。所以现在我有一些看起来像这样的代码行:

// Answer the call by sending a JsepAnswer message.
connection.peerConnection.createAnswer(
    answer => {
        connection.peerConnection.setLocalDescription(answer, () => {
            var signalState: mData.SignalState = {
                FromSessionId: connection.localSessionId,
                ToSessionId: connection.remoteSessionId,
                Message: JSON.stringify(answer)
            };
            me.roomHub.server.jsepAnswer(signalState);
            mUtil.log("Sent JSEP answer: " + signalState.Message);
            connection.readyForIceCandidates.resolve();
        },
        error => {
            mUtil.error("Error setting local description from created answer: " + error + "; answer=" + JSON.stringify(answer));
        });
    },
error => {
    mUtil.error("Error creating answer: " + error);
}, me.mediaConstraints);

错误回调显示此setLocalDescription()错误:

16:14:42.439 WebRTCController.handleJsepOffer():从创建的答案设置本地描述时出错:SetLocalDescription 失败。answer={"sdp":"v=0\r\no=- 439659381 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 音频视频\r\ na=msid 语义:WMS u9fhVrWeLLweqb5ubLkw61Ijsh6BM6vZLhjf\r\nm=音频 1 RTP/SAVPF 103 104 111 0 8 107 106 105 13 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0。 0.0\r\na=ice-ufrag:vOKflTJ56gV0R9i0\r\na=ice-pwd:9nuXPMDvQ2mZATFCQyEzPRQz\r\na=sendrecv\r\na=mid:audio\r\na=rtcp-mux\r\na=crypto: 1 AES_CM_128_HMAC_SHA1_80 内联:m9q9pmLgLuFnfFC09KXKW5p8TjsKk+VdqX0OWv77\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:107 CN/48000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\ na=rtpmap:13 CN/8000\r\na=rtpmap:

现在我只需要弄清楚为什么直接来自该createAnswer()方法的特定 SDP 失败了。

2012-12-20 更新:我在此处创建了该问题的在线演示:http: //srdemo.alanta.com/。我还打开了 Chrome 调试日志记录,结果我看到一堆看起来像这样的错误:

[6584:7308:1220/091356:ERROR:rtc_peer_connection_handler.cc(84)] Native session description is null. [6584:7308:1220/091356:ERROR:rtc_peer_connection_handler.cc(84)] Native session description is null. [6584:7308:1220/091356:ERROR:rtc_peer_connection_handler.cc(84)] Native session description is null. [6584:7308:1220/091356:ERROR:rtc_peer_connection_handler.cc(84)] Native session description is null. [6584:7308:1220/091356:ERROR:rtc_peer_connection_handler.cc(84)] Native session description is null.

不确定他们与我的问题有什么关系,但我正在继续调查。

*编辑 2012-12-20:我已经设法(我认为)缩小了问题的范围。有关更精确的详细信息,请参阅此问题

4

1 回答 1

4

Figured it out. Turns out that SignalR 1.0 RC1 has a bug in it that changes any "+" in a string into a space. So lines in the SDP that looked like this:

a=ice-pwd:qZFVvgfnSso1b8UV1SUDd2+z

Were getting changed into this:

a=ice-pwd:qZFVvgfnSso1b8UV1SUDd2 z

But because not every SDP had a "+" in it on a critical line, sometimes it would work. Everything explained.

The bug has been reported to the good folks working on SignalR (see https://github.com/SignalR/SignalR/issues/1194), and in the meantime, a simple encodeURIComponent() and decodeURIComponent() around the strings in question fixed it.

于 2012-12-21T09:39:02.943 回答