Conversation
No immediate renegotiate
Run standard --fix
…re and rewrite to combine the best parts of each approach.
…imeout option apply to manual ice restart as well.
…eout - This allows any calls to restartIce() after ice failure to continue uninterupted.
…ecks for destryed & _destroying.
…g canidates after ice reconnection. add 'reconnect' event to better signal this event. rename _iceComplete flag to _iceGatheringComplete to better reflect its purpose.
All tests passing on MacOS latest Firefox, Chromium, Safari, & Brave
|
Just noticed this when I was checking if simple-peer has recovery strategy. The intent is nice however, IMHO, I think this only benefits quick work, the recovery strategy often needs to be customized depending on scenario. Some may need to prompt user, some may need to have exponential backoff, or do in a way that is not anticipated. I think adding a task that resolves when connected or rejects when connection attempt failed is better and makes the code simpler. Then user can await and implement whatever strategy they want, either call restartIce with a fixed delay (which is still quick and easy, you can put it in README), or do their own strategy. Something like: var peer = new SimplePeer();
// Wire events
do {
var connected = await peer.connected.then(function() {
// do stuffs
return true;
}).catch(error => {
console.warn("Something went wrong, reconnecting", error);
peer.restartIce(); // Creates new "connected" promise and restart
return false;
});
} while(!connected);User can also easily do something more sophisticated like: var attempts = 0;
var peer = new SimplePeer();
// Wire events
do {
try {
await peer.connected;
}
catch (error) {
var delay = calculate_backoff(++attempts);
if(attempts % 3 == 0) {
switch(await prompt_user()) {
case "troubleshoot":
await run_troubleshooter();
await upload_diagnostics();
delay = 0;
break;
case "alternative":
start_legacy_voip();
return; // pretend this is inside a function
}
}
await sleep(delay);
peer.restartIce();
}
} while(!connected); |
|
Instead of promise, another alternative approach consistent with what's already in sample code is adding an event like The simplest implementation will be: My point is, if recovery mechanism is added as built-in, in the future, people will ask different flavors of recovery mechanism to be implemented, regardless if other users need it or not. If it doesn't exist, then user still has to built their own recovery mechanism. |
|
Thanks for the feedback! At the moment, this PR supports custom reconnection schemes like this:
Steps 1 & 2 could be better explained as I don't think the native events exposed by SimplePeer are well documented. My thought was that this is flexible enough to implement any desired reconnection scheme and fits better with simplePeer's event based model. If I add a "recover" event, when to fire it would be kind of subjective (is it better to fire it on "disconnect" or "failed" or something else?) In my experience with current browsers, disconnect is usually better if signaling is not a bottleneck, but still takes longer than necessary to detect the problem. Watching for multiple dropped video frames or packets might be a better way, but that relies on users of SimplePeer sending lots of data over the wire. |
|
I'm okay with I would like to elaborate My motivation behind If user calls the method => the intention is to That's my two cents. For the part you mentioned, I understand the ICE exchange, but not ncessarily users. Since the The lib hide away all the details, except trickle ICE candidates since that's kinda an edge case that require user knowing what's going on underneath. Also, from the pesudo code above, I believe Then you can put Since most users will start with copy pasting sample code. Also, if user requires even more sophisticated recovery strategy that requires reacting to each native events, then they will already have detailed knowledge about WebRTC and writes their own WebRTC wrapper. |
|
I get the idea of having a simple "recover" event. I'll think about how to add it. The easiest thing would be to trigger the "recover" event when the iceConnectionState becomes "failed", however it often takes up to 30 seconds to reach the "failed" state. I could trigger the "recover" event when the iceConnectionState becomes "disconnected", however it is possible that the connection will quickly become "connected" on it's own without calling iceRestart(), which might surprise users. Which is better do you think? |
|
My opinion is go for the 80/20 rule, where firing Also WebRTC spec has this:
If I understand correctly, the recommended state to perform Also the spec mentioned this for
The long delay of entering failed state you've observed might be related to this. If you have a setup that replicate it, you can test it by calling |
|
@KW-M Is there much more to do on this before merging? I'm looking to add this to my app but would prefer not to have to depend on the PR in my package.json. |
|
@evoactivity not much, mostly needs a code tidy. There was another PR for typescript support that I was hoping would get merged before this PR gets merged but now both me and the other PR author are busy with other things... Currently all unit tests pass, but I haven't had the time to test it thoroughly with my application. If you can test it in your use case I'd appreciate it! The main issue is if the signalling server connection loses messages when the network is interrupted - and network interruption is usually when ICE restart should occur - then it won't work because the other peer won't receive all the required signaling messages. Nothing in this PR fixes an unreliable signal connection, so you'll need to make sure your signalling mechanism is robust for this to work. The promise API is supposed to allow you to account for that and only trigger ice restart when signalling is available again, but it needs some external mechanism to ensure the signaling messages get through. |
|
I should say that the full.js file has the latest changes and I haven't finished copying those changes over to lite.js and index.js |
What is the purpose of this pull request? (put an "X" next to item)
[ ] Documentation update
[ ] Bug fix
[X] New feature
[ ] Other, please explain:
Feat: Add support for automatic or manual ICE Restart
Explained well by @t-mullen "When network conditions change or the current route is congested, it's possible to restart ICE and gather/select a new candidate pair. Apparently this happens very frequently with cellular networks or with certain types of NATs." (feross#579) Also allows automatic reconnection when either peer moves between wifi networks / cell towers.
What changes did you make? (Give an overview)
Add two new configuration options:
iceRestartEnabled: false or "onFailure" or "onDisconnect" - if automatic iceRestart is enabled (defaults to "onFailure" unless trickle is disabled).iceFailureRecoveryTimeout:number - milliseconds to wait for ice restart to complete after the ice state reaches "failed".Added jsDoc typing for the new Peer() configuration options to help with editor autocomplete
Add the method
peer.restartIce()to manually trigger ICE Restart between peers.Which issue (if any) does this pull request address?
feross#579
Is there anything you'd like reviewers to focus on?
based on: Implemented ICE restart [Demonstration Only For Feedback] feross/simple-peer#715 and (Attempt to) Implement ICE Restarts feross/simple-peer#771
Thank you so much for maintaining SimplePeer! I really appreciate it.