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 base media player class where all media players derive from.
 11  *
 12  * @param {object} context The jQuery context.
 13  * @param {object} options This components options.
 14  */
 15 minplayer.players.base = function(context, options) {
 16 
 17   // Derive from display
 18   minplayer.display.call(this, 'media', context, options);
 19 };
 20 
 21 /** Derive from minplayer.display. */
 22 minplayer.players.base.prototype = new minplayer.display();
 23 
 24 /** Reset the constructor. */
 25 minplayer.players.base.prototype.constructor = minplayer.players.base;
 26 
 27 /**
 28  * Get the priority of this media player.
 29  *
 30  * @return {number} The priority of this media player.
 31  */
 32 minplayer.players.base.getPriority = function() {
 33   return 0;
 34 };
 35 
 36 /**
 37  * Returns the ID for the media being played.
 38  *
 39  * @param {object} file A {@link minplayer.file} object.
 40  * @return {string} The ID for the provided media.
 41  */
 42 minplayer.players.base.getMediaId = function(file) {
 43   return '';
 44 };
 45 
 46 /**
 47  * Determine if we can play the media file.
 48  *
 49  * @param {object} file A {@link minplayer.file} object.
 50  * @return {boolean} If this player can play this media type.
 51  */
 52 minplayer.players.base.canPlay = function(file) {
 53   return false;
 54 };
 55 
 56 /**
 57  * @see minplayer.plugin.construct
 58  * @this minplayer.players.base
 59  */
 60 minplayer.players.base.prototype.construct = function() {
 61 
 62   // Call the media display constructor.
 63   minplayer.display.prototype.construct.call(this);
 64 
 65   // Reset the variables to initial state.
 66   this.reset();
 67 
 68   /** The currently loaded media file. */
 69   this.mediaFile = this.options.file;
 70 
 71   // Get the player display object.
 72   if (!this.playerFound()) {
 73 
 74     // Remove the media element if found
 75     if (this.elements.media) {
 76       this.elements.media.remove();
 77     }
 78 
 79     // Create a new media player element.
 80     this.display.html(this.create());
 81   }
 82 
 83   // Get the player object...
 84   this.player = this.getPlayer();
 85 
 86   // Set the focus of the element based on if they click in or outside of it.
 87   var _this = this;
 88   jQuery(document).bind('click', function(e) {
 89     if (jQuery(e.target).closest('#' + _this.options.id).length == 0) {
 90       _this.hasFocus = false;
 91     }
 92     else {
 93       _this.hasFocus = true;
 94     }
 95   });
 96 
 97   // Bind to key events...
 98   jQuery(document).bind('keydown', {obj: this}, function(e) {
 99     if (e.data.obj.hasFocus) {
100       e.preventDefault();
101       switch (e.keyCode) {
102         case 32:  // SPACE
103         case 179: // GOOGLE play/pause button.
104           if (e.data.obj.playing) {
105             e.data.obj.pause();
106           }
107           else {
108             e.data.obj.play();
109           }
110           break;
111         case 38:  // UP
112           e.data.obj.setVolumeRelative(0.1);
113           break;
114         case 40:  // DOWN
115           e.data.obj.setVolumeRelative(-0.1);
116           break;
117         case 37:  // LEFT
118         case 227: // GOOGLE TV REW
119           e.data.obj.seekRelative(-0.05);
120           break;
121         case 39:  // RIGHT
122         case 228: // GOOGLE TV FW
123           e.data.obj.seekRelative(0.05);
124           break;
125       }
126     }
127   });
128 };
129 
130 /**
131  * @see minplayer.plugin.destroy.
132  */
133 minplayer.players.base.prototype.destroy = function() {
134   minplayer.plugin.prototype.destroy.call(this);
135 
136   // Reset the player.
137   this.reset();
138 };
139 
140 /**
141  * Resets all variables.
142  */
143 minplayer.players.base.prototype.reset = function() {
144 
145   // Reset the ready flag.
146   this.playerReady = false;
147 
148   // The duration of the player.
149   this.duration = new minplayer.async();
150 
151   // The current play time of the player.
152   this.currentTime = new minplayer.async();
153 
154   // The amount of bytes loaded in the player.
155   this.bytesLoaded = new minplayer.async();
156 
157   // The total amount of bytes for the media.
158   this.bytesTotal = new minplayer.async();
159 
160   // The bytes that the download started with.
161   this.bytesStart = new minplayer.async();
162 
163   // The current volume of the player.
164   this.volume = new minplayer.async();
165 
166   // Reset focus.
167   this.hasFocus = false;
168 
169   // We are not playing.
170   this.playing = false;
171 
172   // We are not loading.
173   this.loading = false;
174 
175   // If the player exists, then unbind all events.
176   if (this.player) {
177     jQuery(this.player).unbind();
178   }
179 };
180 
181 /**
182  * Create a polling timer.
183  * @param {function} callback The function to call when you poll.
184  */
185 minplayer.players.base.prototype.poll = function(callback) {
186   var _this = this;
187   setTimeout(function later() {
188     if (callback.call(_this)) {
189       setTimeout(later, 1000);
190     }
191   }, 1000);
192 };
193 
194 /**
195  * Called when the player is ready to recieve events and commands.
196  */
197 minplayer.players.base.prototype.onReady = function() {
198   // Store the this pointer.
199   var _this = this;
200 
201   // Set the ready flag.
202   this.playerReady = true;
203 
204   // Set the volume to the default.
205   this.setVolume(this.options.volume / 100);
206 
207   // Setup the progress interval.
208   this.loading = true;
209 
210   // Create a poll to get the progress.
211   this.poll(function() {
212 
213     // Only do this if the play interval is set.
214     if (_this.loading) {
215 
216       // Get the bytes loaded asynchronously.
217       _this.getBytesLoaded(function(bytesLoaded) {
218 
219         // Get the bytes total asynchronously.
220         _this.getBytesTotal(function(bytesTotal) {
221 
222           // Trigger an event about the progress.
223           if (bytesLoaded || bytesTotal) {
224 
225             // Get the bytes start, but don't require it.
226             var bytesStart = 0;
227             _this.getBytesStart(function(val) {
228               bytesStart = val;
229             });
230 
231             // Trigger a progress event.
232             _this.trigger('progress', {
233               loaded: bytesLoaded,
234               total: bytesTotal,
235               start: bytesStart
236             });
237 
238             // Say we are not longer loading if they are equal.
239             if (bytesLoaded >= bytesTotal) {
240               _this.loading = false;
241             }
242           }
243         });
244       });
245     }
246 
247     return _this.loading;
248   });
249 
250   // We are now ready.
251   this.ready();
252 
253   // Trigger that the load has started.
254   this.trigger('loadstart');
255 };
256 
257 /**
258  * Should be called when the media is playing.
259  */
260 minplayer.players.base.prototype.onPlaying = function() {
261   // Store the this pointer.
262   var _this = this;
263 
264   // Trigger an event that we are playing.
265   this.trigger('playing');
266 
267   // Say that this player has focus.
268   this.hasFocus = true;
269 
270   // Set the playInterval to true.
271   this.playing = true;
272 
273   // Create a poll to get the timeupate.
274   this.poll(function() {
275 
276     // Only do this if the play interval is set.
277     if (_this.playing) {
278 
279       // Get the current time asyncrhonously.
280       _this.getCurrentTime(function(currentTime) {
281 
282         // Get the duration asynchronously.
283         _this.getDuration(function(duration) {
284 
285           // Convert these to floats.
286           currentTime = parseFloat(currentTime);
287           duration = parseFloat(duration);
288 
289           // Trigger an event about the progress.
290           if (currentTime || duration) {
291 
292             // Trigger an update event.
293             _this.trigger('timeupdate', {
294               currentTime: currentTime,
295               duration: duration
296             });
297           }
298         });
299       });
300     }
301 
302     return _this.playing;
303   });
304 };
305 
306 /**
307  * Should be called when the media is paused.
308  */
309 minplayer.players.base.prototype.onPaused = function() {
310 
311   // Trigger an event that we are paused.
312   this.trigger('pause');
313 
314   // Remove focus.
315   this.hasFocus = false;
316 
317   // Say we are not playing.
318   this.playing = false;
319 };
320 
321 /**
322  * Should be called when the media is complete.
323  */
324 minplayer.players.base.prototype.onComplete = function() {
325   // Stop the intervals.
326   this.playing = false;
327   this.loading = false;
328   this.hasFocus = false;
329   this.trigger('ended');
330 };
331 
332 /**
333  * Should be called when the media is done loading.
334  */
335 minplayer.players.base.prototype.onLoaded = function() {
336   this.trigger('loadeddata');
337 };
338 
339 /**
340  * Should be called when the player is waiting.
341  */
342 minplayer.players.base.prototype.onWaiting = function() {
343   this.trigger('waiting');
344 };
345 
346 /**
347  * Called when an error occurs.
348  *
349  * @param {string} errorCode The error that was triggered.
350  */
351 minplayer.players.base.prototype.onError = function(errorCode) {
352   this.hasFocus = false;
353   this.trigger('error', errorCode);
354 };
355 
356 /**
357  * @see minplayer.players.base#isReady
358  * @return {boolean} Checks to see if the Flash is ready.
359  */
360 minplayer.players.base.prototype.isReady = function() {
361 
362   // Return that the player is set and the ready flag is good.
363   return (this.player && this.playerReady);
364 };
365 
366 /**
367  * Determines if the player should show the playloader.
368  *
369  * @return {bool} If this player implements its own playLoader.
370  */
371 minplayer.players.base.prototype.hasPlayLoader = function() {
372   return false;
373 };
374 
375 /**
376  * Returns if the media player is already within the DOM.
377  *
378  * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
379  */
380 minplayer.players.base.prototype.playerFound = function() {
381   return false;
382 };
383 
384 /**
385  * Creates the media player and inserts it in the DOM.
386  *
387  * @return {object} The media player entity.
388  */
389 minplayer.players.base.prototype.create = function() {
390   this.reset();
391   return null;
392 };
393 
394 /**
395  * Returns the media player object.
396  *
397  * @return {object} The media player object.
398  */
399 minplayer.players.base.prototype.getPlayer = function() {
400   return this.player;
401 };
402 
403 /**
404  * Loads a new media player.
405  *
406  * @param {object} file A {@link minplayer.file} object.
407  */
408 minplayer.players.base.prototype.load = function(file) {
409 
410   // Store the media file for future lookup.
411   if (file) {
412     this.reset();
413     this.mediaFile = file;
414   }
415 };
416 
417 /**
418  * Play the loaded media file.
419  */
420 minplayer.players.base.prototype.play = function() {
421 };
422 
423 /**
424  * Pause the loaded media file.
425  */
426 minplayer.players.base.prototype.pause = function() {
427 };
428 
429 /**
430  * Stop the loaded media file.
431  */
432 minplayer.players.base.prototype.stop = function() {
433   this.playing = false;
434   this.loading = false;
435   this.hasFocus = false;
436 };
437 
438 /**
439  * Seeks to relative position.
440  *
441  * @param {number} pos Relative position.  -1 to 1 (percent), > 1 (seconds).
442  */
443 minplayer.players.base.prototype.seekRelative = function(pos) {
444 
445   // Get the current time asyncrhonously.
446   var _this = this;
447   this.getCurrentTime(function(currentTime) {
448 
449     // Get the duration asynchronously.
450     _this.getDuration(function(duration) {
451 
452       // Only do this if we have a duration.
453       if (duration) {
454 
455         // Get the position.
456         var seekPos = 0;
457         if ((pos > -1) && (pos < 1)) {
458           seekPos = (currentTime / duration) + parseFloat(pos);
459         }
460         else {
461           seekPos = (currentTime + parseFloat(pos)) / duration;
462         }
463 
464         // Set the seek value.
465         _this.seek(seekPos);
466       }
467     });
468   });
469 };
470 
471 /**
472  * Seek the loaded media.
473  *
474  * @param {number} pos The position to seek the minplayer. 0 to 1.
475  */
476 minplayer.players.base.prototype.seek = function(pos) {
477 };
478 
479 /**
480  * Set the volume of the loaded minplayer.
481  *
482  * @param {number} vol -1 to 1 - The relative amount to increase or decrease.
483  */
484 minplayer.players.base.prototype.setVolumeRelative = function(vol) {
485 
486   // Get the volume
487   var _this = this;
488   this.getVolume(function(newVol) {
489     newVol += parseFloat(vol);
490     newVol = (newVol < 0) ? 0 : newVol;
491     newVol = (newVol > 1) ? 1 : newVol;
492     _this.setVolume(newVol);
493   });
494 };
495 
496 /**
497  * Set the volume of the loaded minplayer.
498  *
499  * @param {number} vol The volume to set the media. 0 to 1.
500  */
501 minplayer.players.base.prototype.setVolume = function(vol) {
502   this.trigger('volumeupdate', vol);
503 };
504 
505 /**
506  * Get the volume from the loaded media.
507  *
508  * @param {function} callback Called when the volume is determined.
509  * @return {number} The volume of the media; 0 to 1.
510  */
511 minplayer.players.base.prototype.getVolume = function(callback) {
512   return this.volume.get(callback);
513 };
514 
515 /**
516  * Get the current time for the media being played.
517  *
518  * @param {function} callback Called when the time is determined.
519  * @return {number} The volume of the media; 0 to 1.
520  */
521 minplayer.players.base.prototype.getCurrentTime = function(callback) {
522   return this.currentTime.get(callback);
523 };
524 
525 /**
526  * Return the duration of the loaded media.
527  *
528  * @param {function} callback Called when the duration is determined.
529  * @return {number} The duration of the loaded media.
530  */
531 minplayer.players.base.prototype.getDuration = function(callback) {
532   return this.duration.get(callback);
533 };
534 
535 /**
536  * Return the start bytes for the loaded media.
537  *
538  * @param {function} callback Called when the start bytes is determined.
539  * @return {int} The bytes that were started.
540  */
541 minplayer.players.base.prototype.getBytesStart = function(callback) {
542   return this.bytesStart.get(callback);
543 };
544 
545 /**
546  * Return the bytes of media loaded.
547  *
548  * @param {function} callback Called when the bytes loaded is determined.
549  * @return {int} The amount of bytes loaded.
550  */
551 minplayer.players.base.prototype.getBytesLoaded = function(callback) {
552   return this.bytesLoaded.get(callback);
553 };
554 
555 /**
556  * Return the total amount of bytes.
557  *
558  * @param {function} callback Called when the bytes total is determined.
559  * @return {int} The total amount of bytes for this media.
560  */
561 minplayer.players.base.prototype.getBytesTotal = function(callback) {
562   return this.bytesTotal.get(callback);
563 };
564