e-Learning Center Media Player

What started it was the need to add captioned video. The original version had the ability to show transcripts, but it was limited to a long string of text. Since the original was built two wonder events happened; the updated release of Captionate, and Flash’s FLVPlaybackCaptioned component. This new version of Captionate allows for the easy creation of the timed XML file that FLVPlaybackCapioned needs to work properly. Voilà! Easy caption creation.

This is not say that the player itself needed updating. The code was staring to show its age. Originally written in ActionScript 2.0, using older components, and with all of the code in one frame on the timeline, it was screaming for a rewrite! The biggest issue what that there where five different versions that used basically the same code, but a few different parameters. This was done because somebody wanted a smaller audio only version, or wanted to play larger videos. They just copied the old code, changed what they wanted to change, and published that.

This new version incorporates the new captioning abilities, while addressing the issues of the old player. First step was to update the code to ActionScript 3.0, along with the components, and then break it apart into classes. I then added feedback of the player’s status during loading. This biggest thing was the ability for the player to change into the different types, while using the same code for all the different ‘types’. This has already proved invaluable in updating and debugging. Then end product is a smooth running player that can incorporate all of the different variations that is the same file size of just one of the old players. Mission accomplished.

The backend also received a major rewrite. When creating a player, you use to have to create the HTML for the player on some types also. Now all you have to do is copy three lines into a new index file. This code references a dynamic back end written in PHP that will dynamically create the required HTML for the player. This allows me to update the player and the backend without having to worry about changing hundreds of html files to make it all work again. Another benefit has been the ability to add an HTML 5 component to the player.

Here is some code from the player’s main class:

// Public Functions ***********************************************************
    // start the player building process
    public function RenderPlayer(gotParams:Boolean):void
    {
      // lets start by showing the loading status
      this.loadStatus = new LoaderStatus(); // crate our loader
      this.loadStatus.rootParent = this.rootObject; // send it the root
      this.loadStatus.SetupLoadingTextbox(this.loaderTextX, this.loaderTextY); // create the text box for the loading text
      this.loadStatus.loadingIndicator = rootObject.loadingMarker; // send it the loading marker movie
      this.loadStatus.SkinColor(this.skinColor, this.skinAlpha); // send it the skin color and alpha (may change)
      this.loadStatus.ShowLoadingStatus('Starting Initialization', this.formatInfo.GetFormat()); // send it our initial message plus any formatting

      if(!gotParams)
      {
        this.loadStatus.RemoveLoader('Unable to load player parameters!');
        return;
      }

      this.transcriptFromCaptionURL = this.baseURL + "transcript.php"; // this script will create a transcript from the captions
      this.baseURL = this.baseURL + this.playerFolder; // create the whole URL
      this.streamURL = this.streamURL + this.playerFolder; // create the whole streaming URL

      // create the urls for what to load
      this.xmlURL = this.baseURL + "courses/" + this.courseNumber.toUpperCase() + "/" + this.mediaDirName + "/mediaInfo.xml"; // Locates "mediaInfo.xml"
      this.transcriptURL = this.baseURL + "courses/" + this.courseNumber.toUpperCase() + "/" + this.mediaDirName + "/transcript.htm"; // Locates the transcript
      this.cssURL = this.baseURL + "courses/" + this.courseNumber.toUpperCase() + "/styles.css"; // Locates the CSS
      this.captionURL = this.baseURL + "courses/" + this.courseNumber.toUpperCase() + "/" + this.mediaDirName + "/captions.xml"; // XML for captions

      trace(this.xmlURL);
      trace(this.cssURL);
      trace(this.captionURL);

      // Start XML Load
      this.xmlObject = new XmlLoader(); // get the loader
      this.xmlObject.GetXML(xmlURL);
      this.xmlObject.loader.addEventListener(Event.COMPLETE, XmlComplete);
      this.xmlObject.loader.addEventListener(Event.OPEN, XmlStarted);
      this.xmlObject.loader.addEventListener(IOErrorEvent.IO_ERROR, XmlLoadError);
      //this.xmlObject.loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, XmlLoadError);
    }

    // Private Functions ******************************************************
    // Load background image, if any
    private function LoadBackground():void
    {
      if(this.showBack)
      {
        // Start Background Loading Process
        this.bgURL = this.baseURL + "courses/" + this.courseNumber.toUpperCase() + "/" + this.bgImageN + "." + this.xmlData.bgFormat.toLowerCase(); // Locates the background image or animation
        this.bgObject = new BgLoader();
        this.bgObject.GetBG(this.bgURL);
        this.bgObject.loader.contentLoaderInfo.addEventListener(Event.OPEN, BgStarted);
        this.bgObject.loader.contentLoaderInfo.addEventListener(Event.COMPLETE, BgLoaded);
        this.bgObject.loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, BgError);
      }
      else
      {
        this.LoadCSS();
      }
    }

    // get the CSS for the player, if any
    private function LoadCSS():void
    {
      if(this.showCSS)
      {
        // Loading CSS
        this.cssObject = new CssLoader();
        this.cssObject.GetCSS(cssURL);
        this.cssObject.loader.addEventListener(Event.OPEN, CssStarted);
        this.cssObject.loader.addEventListener(IOErrorEvent.IO_ERROR, CssError);
        this.cssObject.loader.addEventListener(Event.COMPLETE, CssLoaded);
        this.cssObject.loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, CssSecError);
      }
      else
      {
        // set the text areas
        if(this.setTextArea)
        {
          this.SetTextAreas();
        }
        // start the loading the actual media
        this.LoadMedia();
      }
    }