1 /** The minplayer namespace. */
  2 var minplayer = minplayer || {};
  3 
  4 /** All the media player implementations */
  5 minplayer.players = minplayer.players || {};
  6 
  7 /**
  8  * @constructor
  9  * @extends minplayer.display
 10  * @class The HTML5 media player implementation.
 11  *
 12  * @param {object} context The jQuery context.
 13  * @param {object} options This components options.
 14  * @param {object} queue The event queue to pass events around.
 15  */
 16 minplayer.players.html5 = function(context, options, queue) {
 17 
 18   // Derive players base.
 19   minplayer.players.base.call(this, context, options, queue);
 20 };
 21 
 22 /** Derive from minplayer.players.base. */
 23 minplayer.players.html5.prototype = new minplayer.players.base();
 24 
 25 /** Reset the constructor. */
 26 minplayer.players.html5.prototype.constructor = minplayer.players.html5;
 27 
 28 /**
 29  * @see minplayer.players.base#getPriority
 30  * @return {number} The priority of this media player.
 31  */
 32 minplayer.players.html5.getPriority = function() {
 33   return 10;
 34 };
 35 
 36 /**
 37  * @see minplayer.players.base#canPlay
 38  * @return {boolean} If this player can play this media type.
 39  */
 40 minplayer.players.html5.canPlay = function(file) {
 41   switch (file.mimetype) {
 42     case 'video/ogg':
 43       return !!minplayer.playTypes.videoOGG;
 44     case 'video/mp4':
 45     case 'video/x-mp4':
 46     case 'video/m4v':
 47     case 'video/x-m4v':
 48       return !!minplayer.playTypes.videoH264;
 49     case 'video/x-webm':
 50     case 'video/webm':
 51     case 'application/octet-stream':
 52       return !!minplayer.playTypes.videoWEBM;
 53     case 'audio/ogg':
 54       return !!minplayer.playTypes.audioOGG;
 55     case 'audio/mpeg':
 56       return !!minplayer.playTypes.audioMP3;
 57     case 'audio/mp4':
 58       return !!minplayer.playTypes.audioMP4;
 59     default:
 60       return false;
 61   }
 62 };
 63 
 64 /**
 65  * @see minplayer.plugin.construct
 66  */
 67 minplayer.players.html5.prototype.construct = function() {
 68 
 69   // Call base constructor.
 70   minplayer.players.base.prototype.construct.call(this);
 71 
 72   // For the HTML5 player, we will just pass events along...
 73   if (this.player) {
 74 
 75     this.player.addEventListener('abort', (function(player) {
 76       return function() {
 77         player.trigger('abort');
 78       };
 79     })(this), false);
 80     this.player.addEventListener('loadstart', (function(player) {
 81       return function() {
 82         player.onReady();
 83       };
 84     })(this), false);
 85     this.player.addEventListener('loadeddata', (function(player) {
 86       return function() {
 87         player.onLoaded();
 88       };
 89     })(this), false);
 90     this.player.addEventListener('loadedmetadata', (function(player) {
 91       return function() {
 92         player.onLoaded();
 93       };
 94     })(this), false);
 95     this.player.addEventListener('canplaythrough', (function(player) {
 96       return function() {
 97         player.onLoaded();
 98       };
 99     })(this), false);
100     this.player.addEventListener('ended', (function(player) {
101       return function() {
102         player.onComplete();
103       };
104     })(this), false);
105     this.player.addEventListener('pause', (function(player) {
106       return function() {
107         player.onPaused();
108       };
109     })(this), false);
110     this.player.addEventListener('play', (function(player) {
111       return function() {
112         player.onPlaying();
113       };
114     })(this), false);
115     this.player.addEventListener('playing', (function(player) {
116       return function() {
117         player.onPlaying();
118       };
119     })(this), false);
120     this.player.addEventListener('error', (function(player) {
121       return function() {
122         player.trigger('error', 'An error occured - ' + this.error.code);
123       };
124     })(this), false);
125     this.player.addEventListener('waiting', (function(player) {
126       return function() {
127         player.onWaiting();
128       };
129     })(this), false);
130     this.player.addEventListener('durationchange', (function(player) {
131       return function() {
132         player.duration.set(this.duration);
133         player.trigger('durationchange', {duration: this.duration});
134       };
135     })(this), false);
136     this.player.addEventListener('progress', (function(player) {
137       return function(event) {
138         player.bytesTotal.set(event.total);
139         player.bytesLoaded.set(event.loaded);
140       };
141     })(this), false);
142 
143     // Say we are ready.
144     this.onReady();
145   }
146 };
147 
148 /**
149  * @see minplayer.players.base#playerFound
150  * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
151  */
152 minplayer.players.html5.prototype.playerFound = function() {
153   return (this.display.find(this.mediaFile.type).length > 0);
154 };
155 
156 /**
157  * @see minplayer.players.base#create
158  * @return {object} The media player entity.
159  */
160 minplayer.players.html5.prototype.create = function() {
161   minplayer.players.base.prototype.create.call(this);
162   var element = jQuery(document.createElement(this.mediaFile.type))
163   .attr(this.options.attributes)
164   .append(
165     jQuery(document.createElement('source')).attr({
166       'src': this.mediaFile.path
167     })
168   );
169 
170   // Fix the fluid width and height.
171   element.eq(0)[0].setAttribute('width', '100%');
172   element.eq(0)[0].setAttribute('height', '100%');
173   return element;
174 };
175 
176 /**
177  * @see minplayer.players.base#getPlayer
178  * @return {object} The media player object.
179  */
180 minplayer.players.html5.prototype.getPlayer = function() {
181   return this.elements.media.eq(0)[0];
182 };
183 
184 /**
185  * @see minplayer.players.base#load
186  */
187 minplayer.players.html5.prototype.load = function(file) {
188 
189   if (file) {
190 
191     // Get the current source.
192     var src = this.elements.media.attr('src');
193     if (!src) {
194       src = jQuery('source', this.elements.media).eq(0).attr('src');
195     }
196 
197     // If the source is different.
198     if (src != file.path) {
199 
200       // Change the source...
201       var code = '<source src="' + file.path + '">';
202       this.elements.media.removeAttr('src').empty().html(code);
203     }
204   }
205 
206   // Always call the base first on load...
207   minplayer.players.base.prototype.load.call(this, file);
208 };
209 
210 /**
211  * @see minplayer.players.base#play
212  */
213 minplayer.players.html5.prototype.play = function() {
214   minplayer.players.base.prototype.play.call(this);
215   if (this.isReady()) {
216     this.player.play();
217   }
218 };
219 
220 /**
221  * @see minplayer.players.base#pause
222  */
223 minplayer.players.html5.prototype.pause = function() {
224   minplayer.players.base.prototype.pause.call(this);
225   if (this.isReady()) {
226     this.player.pause();
227   }
228 };
229 
230 /**
231  * @see minplayer.players.base#stop
232  */
233 minplayer.players.html5.prototype.stop = function() {
234   minplayer.players.base.prototype.stop.call(this);
235   if (this.isReady()) {
236     this.player.pause();
237     this.player.src = '';
238   }
239 };
240 
241 /**
242  * @see minplayer.players.base#seek
243  */
244 minplayer.players.html5.prototype.seek = function(pos) {
245   minplayer.players.base.prototype.seek.call(this, pos);
246   if (this.isReady()) {
247     this.player.currentTime = pos;
248   }
249 };
250 
251 /**
252  * @see minplayer.players.base#setVolume
253  */
254 minplayer.players.html5.prototype.setVolume = function(vol) {
255   minplayer.players.base.prototype.setVolume.call(this, vol);
256   if (this.isReady()) {
257     this.player.volume = vol;
258   }
259 };
260 
261 /**
262  * @see minplayer.players.base#getVolume
263  */
264 minplayer.players.html5.prototype.getVolume = function(callback) {
265   if (this.isReady()) {
266     callback(this.player.volume);
267   }
268 };
269 
270 /**
271  * @see minplayer.players.base#getDuration
272  */
273 minplayer.players.html5.prototype.getDuration = function(callback) {
274   if (this.isReady()) {
275     callback(this.player.duration);
276   }
277 };
278 
279 /**
280  * @see minplayer.players.base#getCurrentTime
281  */
282 minplayer.players.html5.prototype.getCurrentTime = function(callback) {
283   if (this.isReady()) {
284     callback(this.player.currentTime);
285   }
286 };
287 
288 /**
289  * @see minplayer.players.base#getBytesLoaded
290  */
291 minplayer.players.html5.prototype.getBytesLoaded = function(callback) {
292   if (this.isReady()) {
293     var loaded = 0;
294 
295     // Check several different possibilities.
296     if (this.bytesLoaded.value) {
297       loaded = this.bytesLoaded.value;
298     }
299     else if (this.player.buffered &&
300         this.player.buffered.length > 0 &&
301         this.player.buffered.end &&
302         this.player.duration) {
303       loaded = this.player.buffered.end(0);
304     }
305     else if (this.player.bytesTotal != undefined &&
306              this.player.bytesTotal > 0 &&
307              this.player.bufferedBytes != undefined) {
308       loaded = this.player.bufferedBytes;
309     }
310 
311     // Return the loaded amount.
312     callback(loaded);
313   }
314 };
315 
316 /**
317  * @see minplayer.players.base#getBytesTotal
318  */
319 minplayer.players.html5.prototype.getBytesTotal = function(callback) {
320   if (this.isReady()) {
321 
322     var total = 0;
323 
324     // Check several different possibilities.
325     if (this.bytesTotal.value) {
326       total = this.bytesTotal.value;
327     }
328     else if (this.player.buffered &&
329         this.player.buffered.length > 0 &&
330         this.player.buffered.end &&
331         this.player.duration) {
332       total = this.player.duration;
333     }
334     else if (this.player.bytesTotal != undefined &&
335              this.player.bytesTotal > 0 &&
336              this.player.bufferedBytes != undefined) {
337       total = this.player.bytesTotal;
338     }
339 
340     // Return the loaded amount.
341     callback(total);
342   }
343 };
344