Code Along with Cam : Simulated Live Streaming

With the release of native live streaming support in Brightcove 4 the question is not if you should take up live streaming but when.

Live streaming offers a video initiative bags of possibilities but true Live Streaming can be costly.   We do work with many partners that can complete this value chain very seamlessly, or for simple projects there's the very easy to use and free Adobe Live Media Encoder that can connect any camera to the servers via a PC.

But then there's the question of trying before buying.   Before investing in establishing what could be a hefty workflow and value chain why not make sure your users would find this of interest?

That's where Simulated Live Streaming can be a great tool.   Either used in a market research / transitional phases or to bring a cost effective Live-like solution to build a real-time viewership, Simulated Live Streaming is relatively simple to do and is available for most versions of Brightcove (Brightcove 499 Express minimum, Pro and higher preferable).

Simulated Live lets you use never before seen VOD content in a way such that all your viewers are watching the same thing at the same time.  Adding in a live chat app like Twitter / Facebook Livestream box and you've got a real time interaction for the community.

To do this you'll need:

  • A Brightcove account
  • Some content in a playlist
  • A PHP server
  • Your Brightcove Media API Read token
  • Some JavaScript knowledge
  • Access to our BEML templating system (Pro Edition and higher)
  • Some spare time

Here is what you need to do.

The main controller for pure Live Streaming in any form is the passage of time.  The content stream is tied to time and all viewers are in sync to that timeline.

So we need to mimic this.  This is where the PHP server comes in.   I used the PHP Media API Wrapper to simplify the Media API call.  The baseline is you need a server to act as your chronometer and make sure all viewers are kept in sync.

The algorithm I put into place to create a stateless sync is:

  • Set 2 fixed points in the timeline: the first is an arbitrary point in the past (I used Jan 01, 2009 00:00:01) and the second is the current time of the request - both represented as timestamps
  • Get the difference of these 2 values
  • Throw away full phases of the playlist to get it present running (use the modulus operator)
  • Once you know how far through the playlist you are break it down to the video level
  • Then break it down to time line of the individual video
  • Pass this back to the player via AJAX

The PHP code is

 # Include the PHP Media API Wrapper
 # Instantiate the class, passing it our Brightcove API tokens
 $bc = new BCMAPI(
  # Set up Constants
  define("TIMESTART", mktime(00, 00, 01, 01, 01, 2009)); #Timestamp of Jan 01, 2009 00:00:01
  # Set up variables
  $tNow = time(); #Time stamp as of UNIX Epoch
  # The algorithm
  # 1 - Get the difference between our Time Start and the Unix EPOCH time - this gives up Time Passed (Tpassed)
  # 2 - Tpassed = duration of video we need to seek through
  # 3 - Total duration of playlist - tells us our search length (if we need to jump to future sequence)
  # 4 - Divide whole multiplier of Playlist Duration into Tpassed - until we have a Mod
  # 5 - Mod is amount of time, seek through videos until again we have less than 1
  # 6 - Remainder is amount in video we need to seek to
  # 7 - Send player seek time via AJAX
  $tPassed = $tNow - TIMESTART;
  $liveList = $bc->find('find_playlist_by_reference_id', 'pl_liveList');
  $totalDuration = 0;
  foreach($liveList->videos as $item => $video) {
   $totalDuration = $totalDuration + round($video->length / 1000);
  #echo "Time Passed = $tPassed <br/>";
  #echo "Total Duration = $totalDuration <br/>";
  $plsection = $tPassed % $totalDuration;
  #echo "Modulus = $plsection <br/>";
  $totalDuration = 0;
  foreach($liveList->videos as $item => $video) {
   $totalDuration = $totalDuration + round($video->length / 1000);
   if ($totalDuration > $plsection) {
    $currentvideo = $video;
    $videoremainder = $totalDuration - $plsection;
  $vidpos = round($currentvideo->length / 1000) - $videoremainder;
  echo "$currentvideo->id,$vidpos";



This is a stateless system that will dish out a current video id and its current position that tracks against the movement of time. 

The statelessness allows us to change the playlist at any time.  And I used a Reference ID for the playlist so I could swap out playlists at any time.

The next step is to put in the JavaScript to sync up the Players.

For this I used a simple AJAX script that calls this at run time

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"

<html lang="en">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="generator" content="TextMate">
    <meta name="author" content="Brightcove">
    <!-- Date: 2009-11-27 -->
    <script language="javascript" type="text/javascript">
    //Browser Support Code
    function ajaxFunction(){
        var ajaxRequest;  // The variable that makes Ajax possible!

            // Opera 8.0+, Firefox, Safari
            ajaxRequest = new XMLHttpRequest();
        } catch (e){
            // Internet Explorer Browsers
                ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                    ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e){
                    // Something went wrong
                    alert("Your browser broke!");
                    return false;
        // Create a function that will receive data sent from the server
        ajaxRequest.onreadystatechange = function(){
            if(ajaxRequest.readyState == 4){
                var responseStr = ajaxRequest.responseText;
                var responseArray = responseStr.split(",");
                playvideo(responseArray[0], responseArray[1]);

        var myRand=parseInt(Math.random()*99999999);  // cache buster      "GET", "simulatedlive.php?rand=" + myRand, true);
    <!-- Start of Brightcove Player -->

    <div style="display:none">


    By use of this code snippet, I agree to the Brightcove Publisher T and C
    found at

    <script language="JavaScript" type="text/javascript" src=""></script>
    <script src=""> </script>

    <object id="myExperience" class="BrightcoveExperience">
      <param name="bgcolor" value="#FFFFFF" />
      <param name="width" value="486" />
      <param name="height" value="412" />
      <param name="playerID" value="52646839001" />
      <param name="publisherID" value="1155521997"/>
      <param name="isVid" value="true" />
      <param name="isUI" value="true" />


    <!-- End of Brightcove Player -->
    <script type="text/javascript">
    var bcExp;
    var modVP;
    var modExp;
    var modCon;
    var doonce = true;
    var position;

    // called when template loads, this function stores a reference to the player and modules.
    function onTemplateLoaded(experienceID) {

        bcExp = brightcove.getExperience(experienceID);

        modVP = bcExp.getModule(APIModules.VIDEO_PLAYER);
        modExp = bcExp.getModule(APIModules.EXPERIENCE);
        modCon = bcExp.getModule(APIModules.CONTENT);
        modExp.addEventListener(BCExperienceEvent.CONTENT_LOAD, onContentLoad);
        modVP.addEventListener(BCMediaEvent.PROGRESS, onMediaProgress)
    function onContentLoad(evt) {

    function onMediaProgress()
        if (doonce) {
            doonce = false;

    function playvideo(id, vpos)
        position = vpos;


Some things to note here:

  • There might be a Stack Overflow error on Internet Explorer for some users.   This doesn't seem to kill the script but worth investigating
  • You have to wait until the video has started to play back before attempting to seek.  To do this I listen to the Media Progress event
  • This is far from a complete solution - there are a few scenarios I can see that would need to be worked out with this one

For those with Brightcove Pro and above you can take the extra step of working the BEML to remove the some of the Media Controls into a more like live stream play back - no seek bar, no forward or back, and the big one

  • The ability to put a playlist behind Single Video Player template.   For Express 499 you'll need to use a standard template and possibly mask the navigation components by HTML divs or the like.

The BEML I used is

  <Theme name="Deluxe" style="Light"/>
    <VBox padding="3">
      <VideoDisplay id="videoPlayer" depth="1" showBack="true" includeFullscreenControls="true" video="{videoList.selectedItem}"/>
      <MediaControls id="mediaControls" height="46" width="486">
        <HBox width="446" height="12" x="10" y="5" gutter="21">
          <Canvas width="31">
            <Label x="0" y="0" id="adMessage" height="16" width="100" vAlign="middle" hAlign="left" text="Live!"/>
            <Spacer height="1"/>
          <Canvas width="31">
            <Label id="adDuration" visible="false" width="31" height="11" vAlign="middle" hAlign="left" text=""/>
        <HBox width="446" height="19" x="5" y="25" gutter="10">
          <ToggleButton id="playButton" showBack="false" iconName="play" toggledIconName="pause" label="controls play" toggledLabel="controls pause" tooltip="controls play tooltip" toggledTooltip="controls pause tooltip" width="100" height="19" autoSize="false" lockHeight="true" iconAlignmentH="left" labelAlignmentH="left" labelOffsetX="20" toggled="{videoPlayer.playing}" click="{}" toggledClick="{videoPlayer.pause()}"/>
          <Button id="maximizeButton" showBack="false" iconName="maximize" tooltip="controls maximize tooltip" width="19" height="17" click="{videoPlayer.goFullScreen()}"/>
          <Button id="volumeButton" showBack="false" iconName="volume" tooltip="controls volume tooltip" width="19" height="17" click="{videoPlayer.toggleVolumeControls()}"/>
          <Button id="menuButton" showBack="false" label="controls menu" height="19" autoSize="true" lockHeight="true" iconAlignmentH="left" labelAlignmentH="left" labelOffsetX="19" data="{}" click="{videoPlayer.toggleMenuPage('Info', data)}"/>
    <List id="videoList" automaticAdvance="true" data="{playlistTabs.selectedItem.videoDTOs}" visible="false">


And the result?  Click here

It doesn't look like much (but open 2 browser windows etc) - but behind the scenes is a player is logging a call with the server to see where in its playlist it should start.   That starting point is the same for all callers that request at the same time.  

Please know that this is not complete live solution.  Due to latency issues players can get out of sync pretty quickly.  You could implement a re-sync utility that just checks things out from time to time.

However I'd recommend doing this only when a player needs to buffer.  Otherwise your users will see stuttering as you try to keep catching them up!