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? See below for more details about how I'm replicating this state, and why I'm asking this:
I'm getting the following error in Chrome 35/node-webkit 0.10.0 when trying to set Ice Candidates when making a call:
Failed to execute 'addIceCandidate' on 'RTCPeerConnection': The ICE candidate could not be added.
Now, I know why it's happening. I'm working on making a ROBUST WebRTC application that can handle some normal user abuse. 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. 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:
Failed to set session description: Failed to set remote answer sdp: Called in wrong state: 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. 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. 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?
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:
var properties = {};
properties.pcConfig = {
"iceServers": [{
"url": "stun:stun.l.google.com:19302"
}]
};
properties.pcConstraints = {
"optional": []
};
peerConn = new RTCPeerConnection(properties.pcConfig, properties.pcConstraints);
peerConn.close();
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, i.e. 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 (i.e. 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.
here is the normal dance (with trickle ICE):
now the problematic case:
glare case:
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 );
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With