October 20, 2012

Multiple YouTube AS3 Players on a Page

The YouTube JavaScript API allows you to interact with the YouTube chromeless or embedded video player programmatically. For example, it provides functions to load, play, pause and stop a video; and triggers events when a video is played or stopped by user interaction.

The events triggered by the API have a catch: they do not specify which player fired the event. So, if you have multiple JavaScript API enabled players on a page, you cannot identify them inside an event handler. This could be a problem, for example, when you have two videos on a page and want to record the number of times each video is played using Google Analytics event tracking. Here is a snippet of code to attach event listener to the videos:

document.getElementById("video-1").addEventListener("onStateChange", "onStateChange");
document.getElementById("video-2").addEventListener("onStateChange", "onStateChange");

The onStateChange function will receive the player's new state (playing, paused, stopped, etc) but not the id or reference of the video. A very simple solution for this problem is to create separate event handler for each video:

document.getElementById("video-1").addEventListener("onStateChange", "onStateChange1");
document.getElementById("video-2").addEventListener("onStateChange", "onStateChange2");

You can use dynamically created JavaScript functions and closures to improve the solution and make it generic. Here is how:

(1) Assign id and playerapiid to each video (keep in mind that api id should be alphanumeric). The two ids should be same for a video; or one should be deducible from the other. Example:

<object type="application/x-shockwave-flash" id="video-1" data="http://www.youtube.com/v/AAAAAAAAAAA?version=3&enablejsapi=1&playerapiid=player1" width="640" height="360">
  <param name="allowScriptAccess" value="always">
  <param name="allowFullScreen" value="true">

<object type="application/x-shockwave-flash" id="video-2" data="http://www.youtube.com/v/BBBBBBBBBBB?version=3&enablejsapi=1&playerapiid=player2" width="640" height="360">
  <param name="allowScriptAccess" value="always">
  <param name="allowFullScreen" value="true">

(2) Each JavaScript API enabled video player fires onYouTubePlayerReady event when it is ready, passing its playerapiid as a parameter. Use the api id to determine the id of the video player which fired the event. Create a function and assign it to that player (keep in mind that certain characters such as underscore will not work in callback names):

function onYouTubePlayerReady(playerApiId) {
  // In our example, a player with apiid = player1234 has the html id = video-1234
  var playerElementId = playerApiId.replace("player", "video-");
  var player = document.getElementById(playerElementId);
  window["onStateChange" + playerApiId] = function(state) {
    console.log("#" + playerElementId + ": new state " + state);
  player.addEventListener("onStateChange", "onStateChange" + playerApiId);


The following example uses four YouTube JavaScript API players, each one displays its playback status independently:

Loading YouTube JavaScript API Player
Loading YouTube JavaScript API Player
Loading YouTube JavaScript API Player
Loading YouTube JavaScript API Player