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 {function} ready Called when the player is ready. 15 */ 16 minplayer.players.html5 = function(context, options, ready) { 17 18 // Derive players base. 19 minplayer.players.base.call(this, context, options, ready); 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 return minplayer.playTypes.videoH264; 46 case 'video/x-webm': 47 return minplayer.playTypes.videoWEBM; 48 case 'audio/ogg': 49 return minplayer.playTypes.audioOGG; 50 case 'audio/mpeg': 51 return minplayer.playTypes.audioMP3; 52 case 'audio/mp4': 53 return minplayer.playTypes.audioMP4; 54 default: 55 return false; 56 } 57 }; 58 59 /** 60 * @see minplayer.plugin.construct 61 */ 62 minplayer.players.html5.prototype.construct = function() { 63 64 // Call base constructor. 65 minplayer.players.base.prototype.construct.call(this); 66 67 // Store the this pointer... 68 var _this = this; 69 70 // For the HTML5 player, we will just pass events along... 71 if (this.media) { 72 this.media.addEventListener('abort', function() { 73 _this.trigger('abort'); 74 }, false); 75 this.media.addEventListener('loadstart', function() { 76 _this.onReady(); 77 }, false); 78 this.media.addEventListener('loadeddata', function() { 79 _this.onLoaded(); 80 }, false); 81 this.media.addEventListener('loadedmetadata', function() { 82 _this.onLoaded(); 83 }, false); 84 this.media.addEventListener('canplaythrough', function() { 85 _this.onLoaded(); 86 }, false); 87 this.media.addEventListener('ended', function() { 88 _this.onComplete(); 89 }, false); 90 this.media.addEventListener('pause', function() { 91 _this.onPaused(); 92 }, false); 93 this.media.addEventListener('play', function() { 94 _this.onPlaying(); 95 }, false); 96 this.media.addEventListener('playing', function() { 97 _this.onPlaying(); 98 }, false); 99 this.media.addEventListener('error', function() { 100 var error = ''; 101 switch (this.error.code) { 102 case MEDIA_ERR_NETWORK: 103 error = 'Network error - please try again later.'; 104 break; 105 case MEDIA_ERR_DECODE: 106 error = 'Video is broken..'; 107 break; 108 case MEDIA_ERR_SRC_NOT_SUPPORTED: 109 error = 'Sorry, your browser can\'t play this video.'; 110 break; 111 } 112 _this.trigger('error', error); 113 }, false); 114 this.media.addEventListener('waiting', function() { 115 _this.onWaiting(); 116 }, false); 117 this.media.addEventListener('durationchange', function() { 118 _this.duration.set(this.duration); 119 _this.trigger('durationchange', {duration: this.duration}); 120 }, false); 121 this.media.addEventListener('progress', function(event) { 122 _this.bytesTotal.set(event.total); 123 _this.bytesLoaded.set(event.loaded); 124 }, false); 125 if (this.autoBuffer()) { 126 this.media.autobuffer = true; 127 } else { 128 this.media.autobuffer = false; 129 this.media.preload = 'none'; 130 } 131 } 132 }; 133 134 /** 135 * Determine if this player is able to autobuffer. 136 * @return {boolean} TRUE - the player is able to autobuffer. 137 */ 138 minplayer.players.html5.prototype.autoBuffer = function() { 139 var preload = this.media.preload !== 'none'; 140 if (typeof this.media.hasAttribute === 'function') { 141 return this.media.hasAttribute('preload') && preload; 142 } 143 else { 144 return false; 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 = document.createElement(this.mediaFile.type), attribute = ''; 163 for (attribute in this.options.attributes) { 164 if (this.options.attributes.hasOwnProperty(attribute)) { 165 element.setAttribute(attribute, this.options.attributes[attribute]); 166 } 167 } 168 return element; 169 }; 170 171 /** 172 * @see minplayer.players.base#getMedia 173 * @return {object} The media player object. 174 */ 175 minplayer.players.html5.prototype.getMedia = function() { 176 return this.options.elements.media.eq(0)[0]; 177 }; 178 179 /** 180 * @see minplayer.players.base#load 181 */ 182 minplayer.players.html5.prototype.load = function(file) { 183 184 if (file && this.isReady()) { 185 186 // Get the current source. 187 var src = this.options.elements.player.attr('src'); 188 189 // If the source is different. 190 if (src != file.path) { 191 192 // Change the source... 193 var code = '<source src="' + file.path + '" '; 194 code += 'type="' + file.mimetype + '"'; 195 code += file.codecs ? ' codecs="' + file.path + '">' : '>'; 196 this.options.elements.player.attr('src', '').empty().html(code); 197 } 198 } 199 200 // Always call the base first on load... 201 minplayer.players.base.prototype.load.call(this, file); 202 }; 203 204 /** 205 * @see minplayer.players.base#play 206 */ 207 minplayer.players.html5.prototype.play = function() { 208 minplayer.players.base.prototype.play.call(this); 209 if (this.isReady()) { 210 this.media.play(); 211 } 212 }; 213 214 /** 215 * @see minplayer.players.base#pause 216 */ 217 minplayer.players.html5.prototype.pause = function() { 218 minplayer.players.base.prototype.pause.call(this); 219 if (this.isReady()) { 220 this.media.pause(); 221 } 222 }; 223 224 /** 225 * @see minplayer.players.base#stop 226 */ 227 minplayer.players.html5.prototype.stop = function() { 228 minplayer.players.base.prototype.stop.call(this); 229 if (this.isReady()) { 230 this.media.pause(); 231 this.media.src = ''; 232 } 233 }; 234 235 /** 236 * @see minplayer.players.base#seek 237 */ 238 minplayer.players.html5.prototype.seek = function(pos) { 239 minplayer.players.base.prototype.seek.call(this, pos); 240 if (this.isReady()) { 241 this.media.currentTime = pos; 242 } 243 }; 244 245 /** 246 * @see minplayer.players.base#setVolume 247 */ 248 minplayer.players.html5.prototype.setVolume = function(vol) { 249 minplayer.players.base.prototype.setVolume.call(this, vol); 250 if (this.isReady()) { 251 this.media.volume = vol; 252 } 253 }; 254 255 /** 256 * @see minplayer.players.base#getVolume 257 */ 258 minplayer.players.html5.prototype.getVolume = function(callback) { 259 if (this.isReady()) { 260 callback(this.media.volume); 261 } 262 }; 263 264 /** 265 * @see minplayer.players.base#getDuration 266 */ 267 minplayer.players.html5.prototype.getDuration = function(callback) { 268 if (this.isReady()) { 269 callback(this.media.duration); 270 } 271 }; 272 273 /** 274 * @see minplayer.players.base#getCurrentTime 275 */ 276 minplayer.players.html5.prototype.getCurrentTime = function(callback) { 277 if (this.isReady()) { 278 callback(this.media.currentTime); 279 } 280 }; 281 282 /** 283 * @see minplayer.players.base#getBytesLoaded 284 */ 285 minplayer.players.html5.prototype.getBytesLoaded = function(callback) { 286 if (this.isReady()) { 287 var loaded = 0; 288 289 // Check several different possibilities. 290 if (this.bytesLoaded.value) { 291 loaded = this.bytesLoaded.value; 292 } 293 else if (this.media.buffered && 294 this.media.buffered.length > 0 && 295 this.media.buffered.end && 296 this.media.duration) { 297 loaded = this.media.buffered.end(0); 298 } 299 else if (this.media.bytesTotal != undefined && 300 this.media.bytesTotal > 0 && 301 this.media.bufferedBytes != undefined) { 302 loaded = this.media.bufferedBytes; 303 } 304 305 // Return the loaded amount. 306 callback(loaded); 307 } 308 }; 309 310 /** 311 * @see minplayer.players.base#getBytesTotal 312 */ 313 minplayer.players.html5.prototype.getBytesTotal = function(callback) { 314 if (this.isReady()) { 315 316 var total = 0; 317 318 // Check several different possibilities. 319 if (this.bytesTotal.value) { 320 total = this.bytesTotal.value; 321 } 322 else if (this.media.buffered && 323 this.media.buffered.length > 0 && 324 this.media.buffered.end && 325 this.media.duration) { 326 total = this.media.duration; 327 } 328 else if (this.media.bytesTotal != undefined && 329 this.media.bytesTotal > 0 && 330 this.media.bufferedBytes != undefined) { 331 total = this.media.bytesTotal; 332 } 333 334 // Return the loaded amount. 335 callback(total); 336 } 337 }; 338