dojo.provide("dojox.av._Media"); dojo.declare("dojox.av._Media", null, { // summary: // Used as a mixin for dojox and AIR media // description: // Calculates the current status of the playing media and fires // the appropriate events. // mediaUrl:"", // // initialVolume: Float? // The initial volume setting of the player. Acccepts between 0 and 1. initialVolume:1, // // autoPlay:Boolean? // Whether the video automatically plays on load or not. autoPlay: false, // // bufferTime: Number? // Time in milliseconds that the video should be loaded before it will // play. May pause and resume to build up buffer. Prevents stuttering. // Note: // Older FLVs, without a duration, cannot be buffered. bufferTime: 2000, // // minBufferTime: Number // Time in milliseconds bwteen the playhead time and loaded time that // will trigger the buffer. When buffer is triggered, video will pause // until the bufferTime amount is buffered. // Note: Should be a small number, greater than zero. minBufferTime:300, // // updateTime: Number // How often, in milliseconds to get an update of the video position. updateTime: 100, // // id: String? // The id of this widget and the id of the SWF movie. id:"", // // isDebug: Boolean? // Setting to true tells the SWF to output log messages to Firebug. isDebug: false, // // percentDownloaded: read-only-Number // The percentage the media has downloaded; from 0-100 percentDownloaded:0, // // _flashObject: read-only-Object // The dojox.embed object _flashObject:null, // // flashMedia: read-only-SWF // The SWF object. Methods are passed to this. flashMedia:null, // _initStatus: function(){ // summary: // Connect mediaStatus to the media. // this.status = "ready"; dojo.connect(this, "onPosition", this, "_figureStatus"); }, // ============== // // Player Getters // // ============== // getTime: function(){ // summary: // Returns the current time of the video // Note: // Consider the onPosition event, which returns // the time at a set interval. Too many trips to // the SWF could impact performance. return this.flashMedia.getTime(); // Float }, // ============= // // Player Events // // ============= // onLoad: function(/* SWF */ mov){ // summary: // Fired when the SWF player has loaded // NOT when the video has loaded // }, onDownloaded: function(/* Number */percent){ // summary: // Fires the amount of that the media has been // downloaded. Number, 0-100 }, onClick: function(/* Object */ evt){ // summary: // TODO: Return x/y of click // Fires when the player is clicked // Could be used to toggle play/pause, or // do an external activity, like opening a new // window. }, onSwfSized: function(/* Object */ data){ // summary: // Fired on SWF resize, or when its // toggled between fullscreen. }, onMetaData: function(/* Object */ data, /* Object */ evt){ // summary: // The video properties. Width, height, duration, etc. // NOTE: if data is empty, this is an older FLV with no meta data. // Duration cannot be determined. In original FLVs, duration // could only be obtained with Flash Media Server. // NOTE: Older FLVs can still return width and height // and will do so on a second event call this.duration = data.duration; }, onPosition: function(/* Float */ time){ // summary: // The position of the playhead in seconds }, onStart: function(/* Object */ data){ // summary: // Fires when video starts // Good for setting the play button to pause // during an autoPlay for example }, onPlay: function(/* Object */ data){ // summary: // Fires when video starts and resumes }, onPause: function(/* Object */ data){ // summary: // Fires when the pause button is clicked }, onEnd: function(/* Object */ data){ // summary: // Fires when video ends // Could be used to change pause button to play // or show a post video graphic, like YouTube }, onStop: function(){ // summary: // Fire when the Stop button is clicked // TODO: This is not hooked up yet and shouldn't // fire. }, onBuffer: function(/* Boolean */ isBuffering){ // summary: // Fires a boolean to tell if media // is paused for buffering or if buffering // has finished this.isBuffering = isBuffering; }, onError: function(/* Object */ data, /* String */ url){ // summary: // Fired when the player encounters an error // example: // | console.warn("ERROR-"+data.type.toUpperCase()+":", // | data.info.code, " - URL:", url); console.warn("ERROR-"+data.type.toUpperCase()+":", data.info.code, " - URL:", url); }, onStatus: function(/* Object */data){ // summary: // Simple status }, onPlayerStatus: function(/* Object */data){ // summary: // The status of the video from the SWF // playing, stopped, bufering, etc. }, onResize: function(){ }, _figureStatus: function(){ // summary: // Calculate media status, based on playhead movement, and // onStop and onStart events // TODO: // Figure in real status from the media for more accurate results. // var pos = this.getTime(); //console.log(pos, this.duration, (pos>this.duration-.5), (this.duration && pos>this.duration-.5)) if(this.status=="stopping"){ // stop was fired, need to fake pos==0 this.status = "stopped"; this.onStop(this._eventFactory()); }else if(this.status=="ending" && pos==this._prevPos){ this.status = "ended"; this.onEnd(this._eventFactory()); }else if(this.duration && pos>this.duration-.5){ this.status="ending" }else if(pos===0 ){//|| this.status == "stopped" if(this.status == "ready"){ //never played }else{ //stopped this.status = "stopped"; if(this._prevStatus != "stopped"){ this.onStop(this._eventFactory()); } } }else{ // pos > 0 if(this.status == "ready"){ //started this.status = "started"; this.onStart(this._eventFactory()); this.onPlay(this._eventFactory()); }else if(this.isBuffering){ this.status = "buffering"; }else if(this.status == "started" || (this.status == "playing" && pos != this._prevPos)){ this.status = "playing"; //this.onPosition(this._eventFactory()); }else if(!this.isStopped && this.status == "playing" && pos == this._prevPos){ this.status = "paused"; console.warn("pause", pos, this._prevPos) if(this.status != this._prevStatus){ this.onPause(this._eventFactory()); } }else if((this.status == "paused" ||this.status == "stopped") && pos != this._prevPos){ this.status = "started"; this.onPlay(this._eventFactory()); } } this._prevPos = pos; this._prevStatus = this.status; this.onStatus(this.status); }, _eventFactory: function(){ // summary: // Creates a generic event object. // var evt = { //position:this._channel.position, //seconds:this.toSeconds(this._channel.position*.001), //percentPlayed:this._getPercent(), status:this.status } return evt; // Object }, _sub: function(topic, method){ // summary: // helper for subscribing to topics dojo.subscribe(this.id+"/"+topic, this, method); }, _normalizeVolume: function(vol){ // summary: // Ensures volume is less than one // if(vol>1){ while(vol>1){ vol*=.1 } } return vol; }, _normalizeUrl: function(_url){ // summary: // Checks that path is relative to HTML file or // convertes it to an absolute path. // if(_url && _url.toLowerCase().indexOf("http")<0){ // // Appears to be a relative path. Attempt to convert it to absolute, // so it will better target the SWF. var loc = window.location.href.split("/"); loc.pop(); loc = loc.join("/")+"/"; _url = loc+_url; } return _url; }, destroy: function(){ // summary: // destroys flash if(!this.flashMedia){ this._cons.push(dojo.connect(this, "onLoad", this, "destroy")); return; } dojo.forEach(this._subs, function(s){ dojo.unsubscribe(s); }); dojo.forEach(this._cons, function(c){ dojo.disconnect(c); }); this._flashObject.destroy(); //dojo._destroyElement(this.flashDiv); } });