iOS Safari App Close - Does not disconnect

I want to make sure I am not missing something and that this may or may not be an IOS thing before I file a bug.

If I start a video call between two Chrome windows, and close 1 of the windows without “leaving”, the app updates accordingly and drops the connection as it should.

If I start a video call between a iOS Safari and a Chrome Window, and I close Safari on the iPhone - the video either a) freezes or b) goes black, but never triggers a disconnect, even minutes after the app is closed.

Is there something I can do to account for this?

Which app are you using? Evicting the participant from the session is not ultimately up to the client. OpenVidu Server will force the disconnection of any type of client if the ping-pong mechanism doesn’t respond in the specifed interval of time. So:

A) Clients should always try to graceully leave their OpenVidu Sessions. So developers should always do their best to call Session.disconnect whenever a user is terminating its connection. For example, browsers have the beforeunload event that is triggered whenever the user closes the browser’s tab, so adding that handler is always a good idea.

B) For managing those cases when the client couldn’t call the Session.disconnect method, OpenVidu Server will attend its ping-pong mechanism with the client to forcely evict it from the Session. After 10~12 seconds without receiving the expected message from the client, it will remove it from the Session and will warn every other user connected to it about it. So, every other user will receive the expected streamDestroyed and connectionDestroyed event for the evicted participant.

Thanks for the quick reply - I am using openvidu-getaroom (openvidu-browser) on 2.12 for testing to make sure it wasn’t any of my custom code.

I see in the example code (getaroom), I do have the call you mention, but it doesn’t appear to trigger only on Safari on iOS in my testing.

// Disconnect participant on browser’s window closed
window.addEventListener(‘beforeunload’, function () {
if (session) session.disconnect();
});

This also appears to result in an issue where, if you refresh the browser window in iOS while in a call, the reload will start a new session, leaving a ghost session connected to the room.

There is a note here about Apple deprecating beforeunload and to use pagehide instead, but that did not work for me either.

https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html#//apple_ref/doc/uid/TP40006511-SW5

On your other comment, I have tested closing the Safari Window and watching the server sessions table for this connection. It does not disappear automatically.

I closed the window and waited 3 full minutes, the connection still shows in openvidu-server. I even turned on the phones Airplane mode to see if there was somehow a chance of a background ping.

Thank you for reporting. We will take a look.

@CSantosM can we test the behavior and file a GitHub issue please?

Hello @AnthonyH,

I’ve made the following test with our demos.openvidu.io environment:

  • Join to session with iOS (v13.3) Safari and with a Chrome browser (ubuntu).
    • Close Safari forcibly. The Chrome browser user can see that the remote stream freezes but after a while (7 ~ 10 seconds) the stream disappear and the session is correctly closed.
    • Refresh Safari browser. The Chrome browser user can see that the remote stream freezes. The Safari user join to the room with a new connection and after a while (7 ~ 10 seconds) the old stream frozen disappear and the session is correctly closed.

Tested with OpenVidu Basic Videoconference , OpenVidu Getaroom and OpenVidu Call.

I can’t reproduce your issue.

Thank you for looking into this. Is there a log file or configuration you could point me in the direction of to understand why the server is not dropping idle connections? Is this the responsibility of openvidu-server or kurentu-media-server? Both of those services are running out of the box configurations.

I am running kurentu-media-server on Ubuntu using your guide, and the java JAR openvidu-server - from this guide: https://openvidu.io/docs/deployment/deploying-ubuntu/

@CSantosM - I am on iOS 13.4 - there is a chance this JUST broke?

Important:
As a quick follow up to my previous comment about “pagehide” not working, I want to correct myself.

Using PageHide DID fix the issue where refreshing the browser on iOS created a second stream, it is still not called on safari force close however, and therefor not closing the server session.

I added a console.log to the beforeUnload and the PageHide event. beforeUnload DOES NOT call on iOS in Safari (13.4) but DOES call the PageHide event, per their documentation beforeUnload is deprecated.

The above being stated, a pagehide listener should be added for those that want to avoid duplicate iOS sessions on page refresh.

To summarize - this code is working for Chrome and iOS Safari to trigger session.disconnect when you leave the page or refresh it.

window.addEventListener('pagehide', function () {
	console.log('PAGE-HIDE');
	if (session) session.disconnect();
});
window.addEventListener('beforeunload', function () {
	console.log('BEFORE-UNLOAD');
	if (session) session.disconnect();
});

On the network timeout issue:
I added a console.log to the sendping() event, and I DO see the ping occurring but not quite sure how I can validate that the pings are being received.

@micael.gallego @pabloFuente

Final update, of the two problems one was my fault, one is a change to safari made in iOS 13.4.

Problem One: Per my testing as of iOS 13.4 the beforeunload event mentioned above no longer calls on refresh, using pagehide per apple documentation fixed this issue. This should probably go in as an issue. I tested this with a friends iOS 13.3 device and beforeunload was still working. I have added a check for pagehide and this issue is resolved for me.

Problem Two: Not disconnecting on heartbeat. This was an issue with my environment. Citrix NetScaler Content Switch does not honor WebSockets with Layer7 content rules, and my ping was being dropped before it made it to the API server.