support Contact Support | system status System Status

Creating a Simulated Live Event

Before you invest in the cost and workflow of creating and running live events, you may want to try a test to gauge the interest of your viewers. This sample shows you how to simulate a live streaming event to do that.

Introduction

What distinguishes live streaming from VOD is the passage of time. The content stream is tied to time and all viewers are in sync to that timeline.

This sample simulates this effect of a live streaming event using VOD content in a Video Cloud playlist, and some JavaScript to keep all viewers at the same point in the playlist regardless of when they start playback.

You will see two players below, followed by an explanation of how this was created.

The players

See the Pen Simulated Live Event by Brightcove Learning Services (@rcrooks1969) on CodePen.

App logic

The logic for creating the simulated live stream is fairly straightforward:

Simulated Live Logic
Simulated Live Logic

Player details

The player is enabled for playlists (to get the Playlist API) but without a playlist display. The JSON for the player configuration is as follows:

{
    "compatibility": true,
    "video_cloud": {
      "policy_key": "{your player policy key will be here}"
    },
    "player": {
      "template": {
        "name": "single-video-template",
        "version": "6.40.3"
      }
    },
    "studio_configuration": {
      "player": {
        "responsive": true,
        "height": 540,
        "width": 960,
        "units": "px"
      }
    },
    "muted": true,
    "plugins": [
      {
        "name": "simulated_live",
        "scripts": [
          "https://{path to your version of the hosted plugin}/simulated-live.js"
        ]
      }
    ]
  }

API methods used

  • catolog.getPlaylist() to fetch the playlist
  • catalog.loadPlaylist() to load the playlist into the player
  • playlist.autoadvance(0) sets playlist to autoadvance with no pause between videos
  • playlist.repeat(true) sets playlist to repeat after finishing
  • player.playlist() gets the video data from the playlist
  • playlist.currentItem sets a specific video in the playlist as the current one
  • player.currentTime() seeks to a specified time in the video

Javascript code for the plugin

videojs.registerPlugin('simulated_live', function() {
    var my_player = this,
    playlist_id = '1664503635149515112', // replace with your playlist id
    video_data,
    video_ranges = [],
    playlist_duration = 0,
    playlist_position,
    current_video_index,
    current_video_position,
    origin_time = new Date('2020-01-01T00:00:00'),
    now_time,
    time_passed,
    logger = document.getElementById('logger');
  
  /**
   * @Desc:  gets the duration of the whole playlist and array of video start times
   * @param {array} video_data array of video data for the playlist videos
   */
  function get_playlist_duration() {
    var i,
      i_max = video_data.length;
    
    for (i = 0; i < i_max; i++) {
      video_ranges[i] = playlist_duration;
      playlist_duration = playlist_duration + video_data[i].duration;
    }
  }
  
  /** 
   * @Desc:  gets time position in current playlist
   */
  function get_playlist_position() {
    now_time = new Date();
    time_passed = now_time - origin_time;
    playlist_position = time_passed % playlist_duration;
    return playlist_position;
  }
  
  /**
   * @Desc:  gets the index of the video that corresponds to the current position in the playlist
   */
  function get_current_video_index() {
    var i,
      i_max = video_ranges.length;
      for (i = 0; i < i_max; i++) {
        if (playlist_position > video_ranges[i] && playlist_position < video_ranges[i + 1]) {
          current_video_index = i;
          return;
        }
      }
  }
  
  /**
   * @Desc:  gets the start position for the video to match the start position in the playlist
   *
   */
  function get_current_video_position() {
    current_video_position = playlist_position - video_ranges[current_video_index];
  }
  
  
  // fetch the playlist
  my_player.catalog.getPlaylist(playlist_id, function(error, playlist){
    if (error) {
      console.log('There was an error retrieving the playlist: ', error);
    }
    
    // load the playlist into the player 
    // the -1 argument prevents the first video from being loaded into the player
    my_player.catalog.load(playlist, -1);
  
    // turn on auto-advance
    my_player.playlist.autoadvance(0);
  
    // turn on replay
    my_player.playlist.repeat(true);
  
    // get the video data from the playlist
    video_data = my_player.playlist();
    
    // get the duration of the playlist and the video ranges
    get_playlist_duration();
    console.log(logger, 'playlist duration: ' + playlist_duration);
    
    
    
    // get the start position in the playlist
    get_playlist_position();
    console.log(logger, 'playlist position: ' + playlist_position);
    
    // get the index of the video where the start position is
    get_current_video_index();
    console.log(logger, 'video index: ' + current_video_index);
    console.log(logger, 'video: ' + video_data[current_video_index].name);
    
    
    // get start position in the video
    get_current_video_position();
    console.log(logger, 'video position:' + current_video_position);
    
    
    // set the start video as the current one
    my_player.playlist.currentItem(current_video_index);
  
    // wait for video to load
    // my_player.on('loadedmetadata', function() {
      // seek to the start point
      my_player.currentTime(current_video_position);
      console.log(logger, 'set position to ' + current_video_position);
      
      // start the video
      my_player.play();
    // }
  });
  });

Page last updated on 06 May 2020