简体   繁体   English

如何在不刷新页面的情况下重置Chrome / node-webkit中的WebRTC状态?

[英]How can I reset the WebRTC state in Chrome/node-webkit, without refreshing the page?

Question: 题:

How does one go about resetting the state of WebRTC components in Chrome -- without reloading the page -- when they're kicked into an invalid state? 如何重置Chrome中的WebRTC组件状态 - 无需重新加载页面 - 当它们被踢入无效状态时如何? See below for more details about how I'm replicating this state, and why I'm asking this: 有关我如何复制此状态的详细信息,请参阅下文,以及为什么我这样问:

Problem description: 问题描述:

I'm getting the following error in Chrome 35/node-webkit 0.10.0 when trying to set Ice Candidates when making a call: 尝试在拨打电话时设置Ice Candidates时,我在Chrome 35 / node-webkit 0.10.0中收到以下错误:

Failed to execute 'addIceCandidate' on 'RTCPeerConnection': The ICE candidate could not be added. 无法在“RTCPeerConnection”上执行“addIceCandidate”:无法添加ICE候选项。

Now, I know why it's happening. 现在,我知道为什么会这样。 I'm working on making a ROBUST WebRTC application that can handle some normal user abuse. 我正在制作一个可以处理一些普通用户滥用的ROBUST WebRTC应用程序。 To replicate this state, I basically have to make a couple WebRTC calls and then kill them real fast and then immediately try another call. 要复制这种状态,我基本上必须进行一些WebRTC调用然后快速杀死它们然后立即尝试另一个调用。 I'm guessing this must kick the PeerConnection and other components into a different state where it's expecting B to happen, but I'm starting over again with A. This is evidenced by the following error message: 我猜这必须将PeerConnection和其他组件放到一个不同的状态,在那里它会发生B,但我重新开始用A.这可以通过以下错误消息证明:

Failed to set session description: Failed to set remote answer sdp: Called in wrong state: STATE_INIT 无法设置会话描述:无法设置远程应答sdp:调用错误状态:STATE_INIT

Now, Most of the WebRTC demos we see on the Internet, like http://apprtc.appspot.com , are stateless, and the browser is refreshed often, which results in resetting the DOM state. 现在,我们在互联网上看到的大多数WebRTC演示,如http://apprtc.appspot.com ,都是无状态的,浏览器经常刷新,导致重置DOM状态。 So, for those developers, the answer is easy. 因此,对于那些开发人员来说,答案很简单。 Just reload the page and call it good. 只需重新加载页面并将其称为好。

Currently, I have to reload the application when the DOM enters this state. 目前,我必须在DOM进入此状态时重新加载应用程序。 However, that's not an acceptable solution, since I'm building a single page application , not a website , 但是,这不是一个可接受的解决方案,因为我正在构建单页应用程序 ,而不是网站

I'm wondering if there is a way to make a call to the API to tell it to reset the state of whatever it is that is throwing these errors? 我想知道是否有办法调用API来告诉它重置抛出这些错误的状态?

Some troubleshooting steps: 一些疑难解答步骤

I tried the following, from the JavaScript console in node-webkit (Chrome 35), to see if I can manually reset the state of the PeerConnection, but it isn't helping: 我尝试了以下命令,从node-webkit(Chrome 35)中的JavaScript控制台,看看我是否可以手动重置PeerConnection的状态,但它没有帮助:

 var properties = {};
 properties.pcConfig = {
     "iceServers": [{
         "url": "stun:stun.l.google.com:19302"
     }]
 };
 properties.pcConstraints = {
    "optional": []
 };

 peerConn = new RTCPeerConnection(properties.pcConfig, properties.pcConstraints);
 peerConn.close();

Here's the output of some of the peerConnection properties: 这是一些peerConnection属性的输出:

peerConn.signalingState     -->  "closed"
peerConn.iceConnectionState -->  "closed"
peerConn.iceGatheringState  -->  "complete"

You are supposed to be able to rollback changes. 您应该能够回滚更改。 That can only happen when roles are not changed, ie when the caller in the first call is still the caller in the subsequent calls, and might not be appropriate in your case, as the error message you are getting is related to a peer connection receiving an answer before emiting an offer (ie a mismatch between caller/callee). 这只能在角色未更改时发生,即第一次调用中的调用者仍然是后续调用中的调用者,并且在您的情况下可能不合适,因为您获得的错误消息与对等连接接收有关在发出要约之前的答案(即来电者/被叫者之间的不匹配)。

Note that close states are final, and a closed peer connection should be deleted as it cannot be reused. 请注意,关闭状态是最终状态,应删除关闭的对等连接,因为它无法重用。

In your case, deleting the original peer connection and making a new one is a must, but not enough. 在您的情况下,删除原始对等连接并创建一个新连接是必须的,但还不够。 You would need to reinitiate the handshake, and to make sure that the messages targeted to the original peer connection is not captured and used by other peer connections. 您需要重新发起握手,并确保不会捕获和使用针对原始对等连接的消息,并由其他对等连接使用。 Multiparty clients have the same design problem. 多方客户具有相同的设计问题。 One way to solve it, and also to solve the glare problem, is to add to the "offer", "answer", "candidate" messages that you exchange offline an "origin" and potentially a "target" field. 解决它的一种方法,也是解决眩光问题的方法是添加到“提供”,“回答”,“候选”消息,您可以离线交换“原点”和可能的“目标”字段。 You must generate IDs yourself, as the peer connection object does not have unique ID by default. 您必须自己生成ID,因为默认情况下对等连接对象没有唯一ID。

here is the normal dance (with trickle ICE): 这是正常的舞蹈(有涓流ICE):

  • A is coming online, creating a peer connection and sore it in a map at the index A_0 A即将上线,创建对等连接,并在索引A_0的地图中将其疼痛
  • B is coming online, same as above with B_0 (make sure IDs are unique) B上线,与B_0相同(确保ID是唯一的)
  • A is calling B A正在呼叫B.
    • A send an offer, with an additional field "origin":"A_0" and a "target":"B_0" 发送报价,附加字段“origin”:“A_0”和“target”:“B_0”
    • B receive offer, setLocalDescription (starts ICE gathering), send answer with origin:B_0, target:A_0, Done. B收到offer,setLocalDescription(开始ICE收集),发送原始答案:B_0,target:A_0,Done。
    • A receive answer, set local description (starts ICE gathering), Done. 收到答案,设置本地描述(开始ICE收集),完成。
    • ICE candidates are being exchanged with the target and origin field set appropriately. 正在与目标和原始领域进行适当交换的ICE候选人。

now the problematic case: 现在有问题的情况:

  • A deletes its A_0 peer connection before receiving B's answer. A在收到B的答案之前删除其A_0对等连接。
  • B sends answers and ICE candidates for A_0, that are discarded by A as A_0 does not exist. B发送A_0的答案和ICE候选,由A丢弃,因为A_0不存在。
  • A restart the dance with A_1 用A_1重新开始舞蹈

glare case: 眩光案例:

  • A and B send simultaneously an offer to each other A和B同时发送报价
  • compare the IDs and chose one according to a reproducible arbitrary rule (the bigger number, the bigger string, use alphabetical order, ….) 比较ID并根据可重现的任意规则选择一个(数字越大,字符串越大,使用字母顺序......)

Note that this design also allow for multiparty calls, as each call would be isolated by the map, and routed by the messaging logic. 请注意,此设计还允许多方调用,因为每个调用都将由映射隔离,并由消息传递逻辑路由。

function handleGenericMsg(msg){
  if(  msg.origin  === username 
    ) {
    trace( 'MAIN - [' + username + '] Ignoring self message: ' + msg.type + '.' );
    return;
  }
  switch(msg.type){
    case 'offer':
      offerHandler(msg);
      break;
    default:
      trace( 'MAIN - [' + targetMid + '] Unsupported message received: ' +     JSON.stringify(msg));
      break;
  }
};

function offerHandler( msg ){
  var targetMid = msg.origin;
  offer = new RTCSessionDescription(msg);
  trace( 'PC   - [' + targetMid + '] Received offer.' )
  var pc = peerConnections[ targetMid ];
  if( !pc ) {
    openPeer( targetMid, false );
    pc = peerConnections[ targetMid ];
  } else {
    // we already had a PC, let's reuse it
  }
  pc.setRemoteDescription( offer );    
  doAnswer( targetMid );
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM