THEOplayer 2.X Demo: Synchronizing multiple players

This page demonstrates how you can synchronize multiple players, using the THEOplayer API

In the example below 4 players are synchronized when the initial play event occurs. A custom button is implemented which, when clicked, will synchronize the four players.

The approach opted in this example is not necesarily the best method to achieve synchronization. As you might observe from the example below, it could be that one player is a few frames behind.
The THEOplayer API gives you all the tools to implement your own approach. For example, you could leverage the playbackRate property so one player catches up to another player over time.

Methods used from the Player API:

  • player.currentProgramDateTime: absolute program date time information of the video (only available when provided through the manifest)
  • player.playbackRate: current playback speed of the video

Events used from the Player API:

  • seeked: thrown when a timeline seek has happened and player.currentTime has a new property

The result:

with player  
 
 
 
 

 

The HTML code:

<button id="sync-btn">Synchronize</button> with player<select id="playerId">
<option value="0">1</option>
<option value="1">2</option>
<option value="2">3</option>
<option value="3">4</option>
</select>
<table>
<tbody>
<tr>
<td>
<div class="content1 video-js theoplayer-skin theo-seekbar-above-controls"> </div>
</td>
<td>
<div class="content2 video-js theoplayer-skin theo-seekbar-above-controls"> </div>
</td>
</tr>
<tr>
<td>
<div class="content3 video-js theoplayer-skin theo-seekbar-above-controls"> </div>
</td>
<td>
<div class="content4 video-js theoplayer-skin theo-seekbar-above-controls"> </div>
</td>
</tr>
</tbody>
</table>

The JavaScript code:

// information on setting up THEOplayer and the player object can be found at https://support.theoplayer.com/hc/en-us/articles/115001933305

var video1 = document.querySelector('.content1'),
    video2 = document.querySelector('.content2'),
    video3 = document.querySelector('.content3'),
    video4 = document.querySelector('.content4');
var player1 = new THEOplayer.Player(video1, {libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/'}),
    player2 = new THEOplayer.Player(video2, {libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/'}),
    player3 = new THEOplayer.Player(video3, {libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/'}),
    player4 = new THEOplayer.Player(video4, {libraryLocation: '//cdn.theoplayer.com/dash/theoplayer/'});
var players = [player1, player2, player3, player4];

// initialize the source of the players
player1.source = {
    sources: [{
        src : 'http://bhm-i.akamaihd.net/hls/live/295198/mwlstream_1/master.m3u8',
        type : 'application/x-mpegurl'
    }]
};
player2.source = {
    sources: [{
        src : 'http://bhm-i.akamaihd.net/hls/live/295199/mwlstream_2/master.m3u8',
        type : 'application/x-mpegurl'
    }]
};
player3.source = {
    sources: [{
        src : 'http://bhm-i.akamaihd.net/hls/live/295200/mwlstream_3/master.m3u8',
        type : 'application/x-mpegurl'
    }]
};
player4.source = {
    sources: [{
        src : 'http://bhm-i.akamaihd.net/hls/live/295201/mwlstream_4/master.m3u8',
        type : 'application/x-mpegurl'
    }]
};

// start playing the four players
for (var i = 0; i < players.length; i++) {
    players[i].muted = true;
    players[i].play();
}

// synchronize to first player
synchronize(0);

// this function gets called when the button is clicked
function syncButtonHandler() {
    var playerId = document.querySelector("#playerId");
    playerId = playerId.options[playerId.selectedIndex].value;
    synchronize(playerId);
}

// attach button listener
document.querySelector("#sync-btn").addEventListener("click", syncButtonHandler);

// this function will sync all the players to a given player ID
function synchronize(id) {
    var seekCount = players.length,
        // function called when seek occurs
        onSeeked = function () {
            seekCount -= 1;
            // if all players are seeked
            if (seekCount <= 0) {
                for (var i = 0; i < players.length; i++) {
                    players[i].playbackRate = 1; // restore video speed
                    players[i].removeEventListener('seeked', onSeeked); // remove listener
                }
            }
        };

    // adjust PDT for all players
    for (var i = 0; i < players.length; i++) {
        players[i].playbackRate = 0; // halt video speed
        players[i].currentProgramDateTime = players[id].currentProgramDateTime; // set PDT 
        players[i].addEventListener('seeked', onSeeked); // await seek event
    }
}