How to remove video on user left

Muaz Khan edited this page Sep 20, 2018 · 2 revisions

You must remove streams using onstreamended event listener. E.g.

connection.onstreamended = function(event) {
    var video = document.getElementById(event.streamid);
    if (video && video.parentNode) {
        video.parentNode.removeChild(video);
    }
};

Above code relies on following snippet:

connection.onstream = function(event) {
    var video = event.mediaElement;
    video.id = event.stream.id; // check this line ---<<------
    document.body.appendChild(video);
};

Please also listen for onleave to remove user from both users list as well as all of his videos:

connection.onleave = function(event) {
    var remoteUserId = event.userid;
    var remoteUserFullName = event.extra.fullName;
    alert(remoteUserFullName + ' left.');
};

You can use streamEvents.selectAll to access and remove all his streams:

connection.onleave = function(event) {
    connection.streamEvents.selectAll({
        userid: event.userid
    }).forEach(function(event) {
        var streamid = event.stream.id;
        var video = document.getElementById(streamid);
        if (video && video.parentNode) {
            video.parentNode.removeChild(video);
        }
    });
};

If you're using beforeunload on your webpage, then please make sure to close sockets manually:

connection.closeBeforeUnload = false;
window.onbeforeunload = function(event) {
    connection.peers.getAllParticipants().forEach(function(participant) {
        connection.multiPeersHandler.onNegotiationNeeded({
            userLeft: true
        }, participant);

        if (connection.peers[participant] && connection.peers[participant].peer) {
            connection.peers[participant].peer.close();
        }

        delete connection.peers[participant];
    });
    connection.attachStreams.forEach(function(stream) {
        stream.stop();
    });
    connection.closeSocket();
};

Best practive

You must not only set id for every HTMLVideoElement but also add additional attribute named as data-userid. E.g.

connection.onstream = function(event) {
    var video = event.mediaElement;
    video.id = event.stream.id; // check this line ---<<------
    video.setAttribute('data-userid', event.userid); // check this line as well ---<<------
    document.body.appendChild(video);
};

Now onstreamended, onleave and onUserStatusChanged listeners can access all videos by data-userid e.g.

document.querySeletorAll('video[data-userid="' + event.userid + '"]').forEach(function(video) {
    if (video && video.parentNode) {
        video.parentNode.removeChild(video);
    }
});

You also need to send your own custom message to all participants as soon as onbeforeunload fires. E.g.

window.onbeforeunload = function(event) {
    connection.send('i-am-leaving'); // check this line ------- <<<<<<< ----------


    // rest of the codes goes here:
    // e.g. closeSocket, disconnectWith, attachStreams.stop etc.
};

Now you can listen for onmessage to check if someone left:

connection.onmessage = function(event) {
    if (event.data === 'i-am-leaving') {
        // remove all of his videos
        document.querySeletorAll('video[data-userid="' + event.userid + '"]').forEach(function(video) {
            if (video && video.parentNode) {
                video.parentNode.removeChild(video);
            }
        });
    }
};

Conclusion

  1. You must listen for all events e.g. onstreamended, onleave and onUserStatusChanged.
  2. onstream event must set both video.id=event.stream.id as well as video.setAttribute('data-userid', event.userid).
  3. If you're using beforeunload on your own page then please make sure to set connection.closeBeforeUnload=false and also manually connection.closeSocket(). It is recommended even if you're not already using beforeunload because this gives you full control over how/when you stop the socket and streams.
  4. Please set connection.session.data=true to open WebRTC data connection. This allows you send messages like 'i-am-leaving' or {userLeft:true} etc. Your onmessage event listener can check for all such notifications and remove videos accordingly.

How to handle screen sharing stopped

If you're using addStream:

connection.addStream({
    screen: true,
    oneway: true,
    streamCallback: function(screen) {
        addStreamStopListener(screen, function() {
            connection.send({
                screebEnded: true,
                streamid: screen.id
            });

            var video = document.getElementById(screen.id);
            if (video && video.parentNode) {
                video.parentNode.removeChild(video);
            }
        });
    }
});

connection.onmessage = function(event) {
    if (event.data.screebEnded === true) {
        var video = document.getElementById(event.data.streamid);
        if (video && video.parentNode) {
            video.parentNode.removeChild(video);
        }
    }
};

Otherwise if you're using getUserMedia API yourselves:

navigator.mediaDevices.getUserMedia({
    video: screenParameters
}).then(function(screen) {
    screen.streamid = screen.id;
    screen.isScreen = true;
    connection.attachStreams.push(screen);
    screenVideoElement.srcObject = screen;

    addStreamStopListener(screen, function() {
        connection.send({
            screebEnded: true,
            streamid: screen.id
        });

        screenVideoElement.srcObject = null;
    });
});

connection.onmessage = function(event) {
    if (event.data.screebEnded === true) {
        var video = document.getElementById(event.data.streamid);
        if (video && video.parentNode) {
            video.parentNode.removeChild(video);
        }
    }
};

addStreamStopListener

Here is the addStreamStopListener function:

function addStreamStopListener(stream, callback) {
    var streamEndedEvent = 'ended';
    if ('oninactive' in stream) {
        streamEndedEvent = 'inactive';
    }
    stream.addEventListener(streamEndedEvent, function() {
        callback();
        callback = function() {};
    }, false);
    stream.getAudioTracks().forEach(function(track) {
        track.addEventListener(streamEndedEvent, function() {
            callback();
            callback = function() {};
        }, false);
    });
    stream.getVideoTracks().forEach(function(track) {
        track.addEventListener(streamEndedEvent, function() {
            callback();
            callback = function() {};
        }, false);
    });
}

via: https://www.webrtc-experiment.com/webrtcpedia/#stream-ended-listener

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.