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 565