JW Player: Building Plugins

Version 4 of the JW Player introduced an API architecture which allows developers to build plugins to the player. Example applications are ad serving, search engine integration and data analytics. LongTailVideo.com serves as a distribution platform for the plugins. This tutorial is aimed at Flash developers who have a solid understanding of Actionscript 3 and want to start developing plugins.

What is a plugin?

A JW Player plugin is a separate SWF file, written in Actionscript 3, which is loaded by the player at runtime. Plugins integrate seamlessly with the player, both in terms of coding (through the API) and graphics (stacked on top of the player). Plugins are loaded into player by setting the plugins flashvar. For example, if you wanted to load two plugins named advertising.swf and delicious.swf, the corresponding flashvar would be plugins=advertising,delicious. An SWFObject embed code would then look something like this:

<script type="text/javascript">
var so = new SWFObject('player.swf','single','700','450','9');
so.addParam("allowfullscreen","true");
so.addParam("allowscriptaccess", "always");
so.addParam("flashvars", "file=myvideo.swf&plugins=advertising,delicious");
so.write('mydiv');
</script>

By default, plugins are hosted at plugins.longtailvideo.com (using Amazon S3). This single-repository architecture enables every player on the internet (>1.000.000) to directly load your plugin by setting the plugins flashvar. For testing or internal purposes, plugins can be set to load from other locations (by setting the variable basedir in Player.as).

Getting started

You can develop plugins using the free Flex SDK or Flash. We have a handy plugin development SDK you can use to quickly start building plugins. It contains a copy of the testing page, some plugin templates and the com.jeroenwijering.events actionscript package (the player API). Since the Flex SDK is free and cross-platform, all you need to start building plugins is a text editor!

Note: If you're looking to develop a plugin in order to serve ads in the JW Player, please contact us beforehand. We have a special SDK for advertisers and advertising networks.

Each plugin should implement com.jeroenwijering.events.PluginInterface:

package com.jeroenwijering.events {
import flash.events.Event;

public interface PluginInterface {
    function initializePlugin(vie:AbstractView):void;
}

}

The initializePlugin() function allows the player to give the plugin a reference. The player automatically calls this function after it has loaded the plugin. The view parameter is a reference to the players' View object. The view allows you to read the config and playlist varilables, send events to the player and listen to events broadcast by the player. A complete overview can be found on the API overview page.

Although any SWF implementing the initializePlugin() function can be loaded, the recommended way of developing an plugin is by creating a class which extends the Sprite or Movieclip class. The most basic plugin to write would look something like this:

package {

import flash.display.Sprite;
import com.jeroenwijering.events.*;

public class Helloworld extends Sprite implements PluginInterface {

    /** Configuration list of the plugin. **/
    public var config:Object;
    /** Reference to the JW Player View object. **/
    private var view:AbstractView;

    /** This function is automatically called by the player after the plugin has loaded. **/
    public function initializePlugin(vw:AbstractView):void {
        view = vw;
        view.sendEvent(ViewEvent.TRACE,"Hello World!");
    };

}

}

To compile this plugin in Flash CS3, copy-paste the code in a new textfile called Helloworld.as. Next, create a new FLA file (with Actionscript 3.0 / Flash Player 9 support) and set its Document class property to point to your new .as class.

Interacting with the player

The View class is the bridge by which the player and your plugin communicate. The following handful of properties and functions give you full access to the player:

  1. Access the object with all configuration parameters of the player through view.config.
  2. Access the playlist array of the player through view.playlist.
  3. Send directives to the player with view.sendEvent(event,value).
  4. Subscribe to events from the Controller with view.addControllerListener(event,function) (overview).
  5. Subscribe to events from the Model with view.addModelListener(event,function) (overview).
  6. Subscribe to events from the View with view.addViewListener(event,function) (overview).

The 4.3 player introduced some new handlers through which plugins can have richer interaction with the stage and with each other:

  1. Request a reference to another plugin with view.getPlugin(name). This is useful for plugins that have public methods, such as the Controlbar with hide() and addButton().
  2. Request the configuration of a plugin through view.getPluginConfig(plugin). Usually you'd use this as view.getPluginConfig(this) to request the positioning and additional variables for the plugin.

Again note that a complete overview of all available calls can be found on the API reference page. This handy diagram lists all variables in the config object and all events events of the view, model and controller.

Here's a plugin code snippet that listens to changes in the playback position:

public function initializePlugin(vw:AbstractView):void  {
    view = vw;
    view.addModelListener(ModelEvent.TIME, timeHandler);
};

private function timeHandler(evt:ModelEvent):void {
    trace("the new position is: "+evt.data.position);
};

Here's another snippet that loads a specific video once the user clicks a button:

private var button:Sprite;
private var video:String = "http://www.mysite.com/video/myVideo.flv";
private var view:AbstractView;

public function initializePlugin(vw:AbstractView) {
    view = wv;
    button.addEventListener(MouseEvent.CLICK,loadVideo);
};

private function loadVideo():void {
    view.sendEvent(ViewEvent.LOAD,video);
};

This last snippet requests the plugins' configuration settings so it can be rescaled after a resize:

public var config:Object;
private var rectangle:MovieClip;
private var view:AbstractView;

public function initializePlugin(vw:AbstractView) { 
    view = vw;
    view.addControllerListener(ControllerEvent.RESIZE,resizeHandler);
};

private function resizeHandler(evt:ControllerEvent) {
    // A plugin config contains the x,y,width,height position of the plugin and is automatically updated.
    rectangle.x = config['x'];
    rectangle.y = config['y'];
    rectangle.width = config['width'];
    rectangle.height = config['height'];
};

Note that the plugins package contains a string of example plugins you can borrow code snippets from.

There's also a separate tutorial that describes step by step how to build the Yousearch plugin. The Yousearch plugin shows a small Youtube search box on stage, used to load Youtube videos.

Loading data

Basic configuration parameters for a specific plugin can be loaded through the same flashvars mechanism the player uses itself. Variables for a specific plugin must be prepended with the name of the plugin and a dot. So if your plugin is called delicious, your variable names must start with the delicious. string. Example:

<script type="text/javascript">
var so = new SWFObject('player.swf','single','700','450','9');
so.addParam("allowfullscreen","true");
so.addParam("flashvars", "file=video.flv&plugins=delicious&delicious.user=jeroenw&delicious.tags=coolstuff");
so.write('mydiv');
</script>

All the flashvars set in HTML will end up sitting in the view.config object, so you can request any flashvars from there. For example, this is how the delicious plugin could request its flashvars:

public function initializePlugin(vw:AbstractView) {
    var user = view.config['delicious.user'];
    var tags = view.config['delicious.tags'];
};

The 4.4 player will automatically push all flashvars to your plugin, so you won't have to get them from the global config file. Your config needs to be public then! You can also set defaults, which will automatically be overwritten. Example:

public var config:Object = {
    user:'default',
    tags:undefined
};

public function initializePlugin(vw:AbstractView) {
    // when called, the player has already updated the flashvars.
    var user = config['user'];
    var tags = config['tags'];
};

Besides providing an automated mechanism for pushing plugin flashvars, the 4.4+ setup has two other advantages:

  1. The config object will also contain the x,y,width and height properties of the plugin, so it is very easy to resize the plugin after requesting this object. Here's more info on resizing.
  2. The config object continues working even if the plugin name is changed. If, for example, our plugin was renamed from delicious to mydelicious, the first plugin retrieval method doesn't work anymore, but the second will.

If you want to pull more complex data into the plugin, it is best to let the plugin itself load the data through an external XML file. Keep in mind the Crossdomain security restrictions of Flash then: the domain serving the XML needs a crossdomain.xml file that must allow access from the domain from which the player.swf (NOT the plugin!) is served.

Building

We have a separate, short explanation on how to compile your plugin using the free, crossplatform Flex SDK.

This page is made separate because it also explains how to compile any of the open-source plugins we offer at this site.

Testing

For testing your plugin against various versions and setups of the player, you can use the testing page, which is part of the plugin development SDK. Tests can be made against all versions of the player and with any combination of player/skin/plugins you'd like. Inserting your plugin in the testing page is simply a matter of changing the settings.js file that is included with the SDK. This is a dictionary that lists the location of all available plugins, skins, players and settings. It needs to know the location of your plugin SWF and the location of a plugin XML file, which describes your plugin. An example of such XML file is listed here, and more examples can be found in the plugin development SDK.

<plugin>
	<title>Plugin title</title>
	<filename>plugin.swf</filename>
	<version>1</version>
	<compatibility>Compatible with 4.X</compatibility>
	<author>Me</author>
	<description>A short description of the plugin, in a few lines.</description>
	<href>http://www.mywebsite.com/plugins/myplugin/</href>

	<flashvars>
		<flashvar>
			<name>file</name>
			<default>myfile.xml</default>
			<description>A flashvar for this plugin</description>
		</flashvar>
		<flashvar>
			<name>image</name>
			<default></default>
			<description>Another flashvar, with no default value.</description>
		</flashvar>
	</flashvars>

</plugin>

Debugging

Version 4.5 of the player also introduced plugin debugging capabilities in the form of the com.jeroenwijering.utils.Logger class. Include this class in your player and send a call to Logger.log() every time you want to log an event or error. The call takes a message and a type (which can be used to identify your plugin):

Logger.log('XML file loaded and parsed','MyPlugin');

If you use a debug version of the Adobe Flash player, you will have an additional rightclick menu item, saying "Logging to ...". The following options are available:

  • none: No logging is performed. This is the default.
  • arthropod: logs are sent to the Arthropod AIR application. It's a small, free and very useful tool.
  • console: logs are sent to the Firefox / Firebug console.
  • trace: logs are sent to actionscript's built-in tracing command. You can write these to a logfile in turn.

If you want to debug with a non-debug player, set the flashvar debug=xxx in your source code, xxx being one of the above options. It is recommended you install a debug player though, since that enables you to also debug players whose flashvars you cannot alter.

Submit your plugin

When you're done testing your plugin and would like to get people start using it, submit your plugin to the LongTailVideo Addons section. Once loaded onto Longtails' repository, your plugin can be loaded into any JW Player out there through the plugins flashvar. You will instantly reach an audience of millions!

Good luck coding! And if you have any questions about building plugins, please visit the plugins forum.