WebRTC reconnect after lost connection (reconnection attempt) - javascript

I have a working WebRTC JavaScript application. Here is the problem: if during a web call there is a bad network connection, the call is stopped without WebRTC attempting to reconnect.
I would like to improve the code of my application by adding an automatic reconnection attempt system, however, in order to do so I need to understand some theory about WebRTC (and I think this can be very useful for many other developers).
Here are my questions:
Does WebRTC have a native functionality to attempt reconnection if the network is bad or should I listen for some "disconnection tigger" and call "a function" to start a new connection from zero?
If things cannot be done magically, what is/are the right "disconnection tigger/s" and "the function" from which the reconnection attempt process should restart? Is there something that can (or should) be taken from the previous connection?
I have read about an {iceRestart: true} parameter. Should this be used for the first call (then WebRTC will magically handle disconnection by attempting to reconnect) or should I use it ONLY when my code attempts to reconnect (on the 2nd, 3rd times...)?
What is the difference between connectionState "disconnected", "failed" and "closed" and does it have something to do with attempting to reconnect with bad network?
What is the best way to avoid attempting to reconnect in an infinite loop if there is no hope to reconnect (i.e: internet completely down)?
What is the difference between oniceconnectionstatechange and onconnectionstatechange? which is relevant in my case?
Thanks!
Luca

I was able to find the (JavaScript) solution through experimenting...
1) Does WebRTC have a native functionality to attempt reconnection if the network is bad or should I listen for some "disconnection tigger" and call "a function" to start a new connection from zero?
Yes, it does it by default in JavaScript, unless your code handles disconnection by proactively terminating the call through additional lines of instructions.
2) If things cannot be done magically, what is/are the right "disconnection tigger/s" and "the function" from which the reconnection attempt process should restart? Is there something that can (or should) be taken from the previous connection?
Things already happen under the hood (by magic). If the code terminates the call, it is probably because the disconnection trigger (ICE connection state = disconnected OR connection state = disconnected) triggers some additional code from the app you copy/pasted from somewhere.
3) I have read about an {iceRestart: true} parameter. Should this be used for the first call (then WebRTC will magically handle disconnection by attempting to reconnect) or should I use it ONLY when my code attempts to reconnect (on the 2nd, 3rd times...)?
Not useful in this scenario.
4) What is the difference between connectionState "disconnected", "failed" and "closed" and does it have something to do with attempting to reconnect with bad network?
You have to listen for connectionState = disconnected, the other ones don't matter for this purpose.
5) What is the best way to avoid attempting to reconnect in an infinite loop if there is no hope to reconnect (i.e: internet completely down)?
No problem, the reconnection WebRTC handles automatically will not cost anything in terms of signaling, therefore, you can try to reconnect as many times as you want, the user will eventually exit the call on his own if things are too slow.
6) What is the difference between oniceconnectionstatechange and onconnectionstatechange? which is relevant in my case?
No difference in this case, the only difference is that the ice state change is triggered right before the connection state change.
--
I hope this will be helpful to somebody!

Related

Keep Node Server running "watching" for things to occur

I think this question is due to a lack of understanding on node, but i'm working on created a motion sensor with the raspberry pi and node.
I don't understand how to keep my node server running. I can get it to work as intended using setInterval but I don't think this is how I should be doing it.
Basically I want to be able to start the program with node index.js and have it continue watching the GPIO pins that the sensor is connected to see if something happens. If something happens then it does something, but keeps watching the sensor in case more happens.
What I have done to keep it running is similar to this:
var foo = require('require necessary things up here');
setInterval(function(){
//code for detecting sensor stuff here
}, 1000)
This works, but I know I don't think it's the right way to do it.
If I do something like the below it just executes the functions, logs to the console, but doesn't watch for changes and just exits out.
var foo = require('require necessary things up here')
function checkForSensorStuff(){
//code for detecting sensor stuff here
console.log('checking stuff')
}
How can I keep the server running so that it just continually watches for changes in a function without using setInterval?
A node process exits when it has nothing else left to do. You start a node process by running a startup script line by line. When that script finishes executing, if there's nothing else to do (no timers, no open sockets listening for incoming connections, etc...), then it shuts down because there's nothing left that could cause an event and cause some action on the server.
So, if you want your server to continue running, you have to give it some way for future events to occur. As you've discovered a recurring timer is one way to do that. There should be no reason to use a timer purely for keeping your server running. Instead you need to configure something in your server that will trigger events in the future. If you don't have anything that will cause future events, then you may need to use setInterval() to regularly poll some status to decide if there's something waiting to do.
If you're trying to monitor GPIO status on your Raspberry Pi in node.js, you can use the pigpio library and it will offer an event driven way of watching for GPIO changes. This should automatically keep your server running.
Another option for getting events upon GPIO changes is the onoff library.
I have a Raspberry Pi being used as a temperature controller that reads two GPIO temperature probes. I'm just using a setInterval() timer to poll the temperature readings every 10 seconds and that works just fine too.
I don't understand how to keep my node server running
You need to open an handle to a resource like a socket or a file. If there is no active handles opened, node exits. In your example setInterval is timer which prevents node to exit.
see also process._getActiveHandle
https://github.com/myndzi/wtfnode

autobahn (node) not detecting dropped connect, infinite wait, can I set a timeout?

I'm using this AutobahnJS code in node to receive data from a service. It works great, getting multiple events per second. When my internet temporarily disconnects Autobahn does not detect the lost connection and does not write "Websocket connection dropped" to console, it just hangs. Indefinitely.
Is there a timeout one can set, if no data arrives after 1 minute, reconnect? Or can I use a setTimeout function to ping a server and if no pong returns close the connection and try to reopen it?
I googled till my fingers were bleeding, but I didn't find a straightforward answer to this question. Thank you very much!
connection.onopen = function(session) {
session.subscribe(arg, someEvent);
}
connection.onclose = function() {
console.log("Websocket connection dropped");
}
connection.open();
It is not possible to recognize an unclean disconnect without some data being sent. The WebSocket ping/pong mechanism at the protocol level is not exposed in the browser, and Autobahn|JS does not have any different handling when running in Node.js.
For the time being, you need to implement your own ping/pong mechanism at the application level.

WebRTC: simultaneous renegotiation issue

Use Case: three peers are in video chat with other two in same room, server sends a message and all three change mode to audio,
for now, only chrome supports renegotiation, so for firefox, i just close the connection and create new peer connection, but after I check both sides are chrome and change mode,
If I am changing mode of only one peer at a time, it works smoothly.
but when, message comes from server, both peers try to renegotiate simultaneously and it didn't work, I got something like wrong state : STATE_SENTINITIATE
To handle that problem, I did a workaround where, whenever peerconnection has to renegotiate, it checks if it is the caller
if yes, it goes ahead with renegotiation.
else(if it is answerer), it would change the offered stream and signal the caller to renegotiate.
The above workaround works for few renegotiations, but for some cases, it throws error at setting local description on the answerer's side, claiming wrong state to be either STATE_INPROGRESS or STATE_SENTACCEPT.
how do I resolve this issue?
Since renegotiation is a state-machine, having both sides initiate renegotiation at the same time can collide, and you end up with invalid-state errors. This is called glare.
Your workaround is one way to deal with glare, essentially using signaling to make sure renegotiation is always initiated from the same end (typically the offerer's side).
You say you're still seeing occasional invalid-state errors even with this workaround. Since renegotiation is a round-trip between peers, there's a window of time where if you're also responding to signaling requests for new renegotiation, I suppose you could still get invalid-state errors if you try to renegotiate again too soon.
You can check the pc.signalingState attribute to know what state your peerConnection is in at any time. I would look at that when you receive incoming messages, to see if this is the problem. If it is, I would hold off on renegotiating until your connection is in the "stable" state again. You can use pc.onsignalingstatechange to react to state changes.
Another solution I've heard of (but not tried) to solve glare would be to let peers renegotiate independently, and when they do glare, let the offerer always win. e.g. the answerer would cancel any attempts it was making on receiving an incoming offer (by somehow reverting itself back to its previous stable state), whereas the offerer would ignore any incoming offers during its own attempt.
By the way, renegotiation is supported in Firefox as well now (38+) so you could try it there as well to see if you get the same problems.

Write After End error in node.js webserver

I am struggling with my node.js hobby project due to a "write after end" Error. I have a created a node.js webserver that amongst other things, sends commands received from a HTML page onwards to another process using the following code:
var netSocket = require('net').Socket();
netSocket.connect(9090);
netSocket.write(messages);
netSocket.end();
This works until the traffic starts to increase (i.e. the amount of messages being sent and or the size of the messages). At this point I get the following error:
Error: write after end
at writeAfterEnd (_stream_writable.js:132:12)
at Socket.Writable.write (_stream_writable.js:180:5)
at Socket.write (net.js:615:40)
at Socket.<anonymous> (/Users/mark/Documents/GitHub Repos/voice_controlled_zumo/speech_module/web_server_HTTPS.js:66:15)
at Socket.emit (events.js:95:17)
at Socket.onevent (/Users/mark/Documents/GitHub Repos/voice_controlled_zumo/node_modules/socket.io/lib/socket.js:327:8)
at Socket.onpacket (/Users/mark/Documents/GitHub Repos/voice_controlled_zumo/node_modules/socket.io/lib/socket.js:287:12)
at Client.ondecoded (/Users/mark/Documents/GitHub Repos/voice_controlled_zumo/node_modules/socket.io/lib/client.js:193:14)
at Decoder.Emitter.emit (/Users/mark/Documents/GitHub Repos/voice_controlled_zumo/node_modules/socket.io/node_modules/socket.io-parser/node_modules/component-emitter/index.js:134:20)
My guess is that the server at 9090 is being overwhelmed by the amount of traffic, giving rise to the error. As a complete newbie in the node.js world I'd really appreciate any hints for how I could resolve this issue.
Note also that the webserver is serving pages over SSL (in case that makes any difference).
Thanks for taking the time to read this!
Mark
NodeJS is a non-blocking async platform.
In your case,
netSocket.write(messages);
is an async method; therefore, netSocket.end() is called before write is complete.
The correct use would be:
netSocket.write(messages, function(err) { netSocket.end(); });
The second argument here is a callback function that will be called once the 'write' method finishes its job.
I would recommend you read/watch more about NodeJS, async styles and callbacks.
Here is a great place to start: https://www.youtube.com/watch?v=GJmFG4ffJZU
And of course, the NodeJS API docs regarding net sockets.
First, I think there is misinformation in another answer about socket.write() and socket.end(). It is perfectly normal and OK to do them back to back in the same tick:
socket.write(everythingIPlanToSend);
socket.end();
You do not need to provide a callback to write. The callback will tell you when the data has been fully flushed out the connection, but that is an optional notification that typical programs don't need to concern themselves with.
However, looking at your stack trace, I think your event handling control flow is broken in this manner. You have a socket.io client connected, and that emits events which you listen for. When those events fire you send them onward to your upstream server. Then you end the upstream socket connection. At that point, you must unbind (removeListener) your socket.io connection listener so that as more events arrive you don't attempt to send them up the connection you have already closed.
Another way to say it is whenever you call .end() on your upstream socket, you have to make sure that future incoming events from the browser do not make use of that same socket. OR you have to change your code to use the same upstream socket for all events from the corresponding browser socket (which is probably more efficient/correct), BUT in that case don't call .end() on it until the browser socket actually disconnects.
I had similar issue with node module compression, after i update it to the latest version 1.6, the issue was resolved
npm install compression#1.6.0

What does connect_timeout do/mean in Socket.IO 1.0.6?

I'm trying to find the definition of connect_timeout, when is it fired, what's the use for it?
Reading here : http://socket.io/docs/client-api/#manager(url:string,-opts:object)
Right now I have an app I tried to run without turning on the server, and it tries to connect and the event "Reconnecting" is fired for 4 attempts, one every 2 seconds. Then it says "Failed Reconnecting" when it hits the 4 attempt mark and fires the event "reconnect_failed".
I haven't been able to hit the connect_timeout event. How do I do that? When does it happen?
I was hoping Socket.IO had some sort of function of "CONNECTING" and then if it failed it would continue attempting "CONNECTING" and if that failed it would say "CONNECTION FAILED" and if it connected successfully at some point, it would then call "RECONNECTING" instead and if that failed after a certain amount of attempts it would say "RECONNECTING FAILED". Is that something that has to be programmed by me? I haven't seen it built in.
Connection timeout is when a client is connected to the server and it takes too long for a response to be received, causing the client to disconnect because it has stopped receiving anything from the server. This can be caused by faulty internet or if the client loses connection to the server (i.e. the clients internet becomes disconnected). This is true for most server based communications and is likely the same for socket.io.

Categories

Resources