mediastream.lzx
<library>
<class name="mediastream" extends="node">
<passthrough when="$as3">
import flash.media.*;
import flash.events.*;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.utils.setTimeout;
</passthrough>
<doc>
<tag name="shortdesc">
<text>Allows video playback, live broadcast or recording .</text></tag>
<text>
<p><tagname>mediastream</tagname> allows applications to stream video from HTTP or RTMP servers. Classes like <sgmltag class="element" role="lz.videoview"><videoview></sgmltag> use mediastreams to handle the connection to the server.</p>
<example><programlisting class="code">
<canvas>
<mediastream name="ms" autoplay="true" type="http" url="http://www.archive.org/download//JudgeMediaTestVideoFile_0/video.flv"/>
<videoview type="http" autoplay="true" width="320" height="240" stream="canvas.ms"/>
</canvas>
</programlisting></example>
</text>
</doc>
<attribute name="url" value="
" type="string"/>
<attribute name="type" value="http
" type="string"/>
<attribute name="autoplay" value="false
" type="boolean"/>
<attribute name="autorewind" value="true
" type="boolean"/>
<attribute name="autoplayStart" value="'either'
"/>
<attribute name="autoplayPause" value="false
" type="boolean"/>
<attribute name="autoplayLength" value="'end'
"/>
<attribute name="autoplayReset" value="true
"/>
<attribute name="totaltime" value="0
" type="number"/>
<attribute name="time" value="0
" type="number"/>
<attribute name="buffertime" value="0.1
" type="number"/>
<attribute name="progress" value="0
" type="number"/>
<attribute name="fps" type="number" value="0
"/>
<attribute name="paused" value="false
" type="boolean"/>
<attribute name="playing" value="${(this.mode == 'playing') && (!this.paused)}"/>
<attribute name="recording" value="${this.mode == 'recording'}"/>
<attribute name="broadcasting" value="${(this.mode == 'broadcasting') || (this.mode == 'recording')}"/>
<attribute name="mode" value="
" type="string"/>
<attribute name="debug" value="false
"/>
<attribute name="cam" value="null
"/>
<attribute name="mic" value="null
"/>
<attribute name="streamname" value="
" type="string"/>
<attribute name="rtmp" value="null
"/>
<attribute name="muteaudio" value="false
"/>
<attribute name="mutevideo" value="false
"/>
<attribute name="_nc" value="null
"/>
<attribute name="_nullnc" value="null
"/>
<attribute name="_flashstream" value="null
"/>
<attribute name="_timedel" value="null
"/>
<attribute name="_pendingstreamname" value="
" type="string"/>
<attribute name="_basetime" value="0
" type="number"/>
<attribute name="_creationCallback" value="null
"/>
<event name="onurl"/>
<event name="ontype"/>
<event name="oncuepoint"/>
<event name="onstart"/>
<event name="onstop"/>
<event name="oninsufficientbandwidth"/>
<event name="onmetadata"/>
<event name="onmode"/>
<event name="onbuffertime"/>
<method name="_resetStream">
if (this._flashstream != null) {
this._flashstream.play(false);
this._flashstream.close();
this._flashstream = null;
}
</method>
<method name="play" args="start='either', pause=false, length='end', reset=true">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w play url=%w" +
"start=%w pause=%w length=%w reset=%w",
this, this.url, start, pause, length, reset);
}
}
// Map symbolic start values to Flash integers.
switch (start) {
case "recorded":
start = 0;
break;
case "live":
start = -1;
break;
case "either":
start = -2;
break;
default:
if (start < 0) {
if ($debug) {
Debug.warn("mediastream.play %w called with Flash-dependent start param: %w", this, start);
}
}
break;
}
// Map symbolic length values to Flash integers.
switch (length) {
case "end":
length = -1;
break;
default:
if (length < 0) {
if ($debug) {
Debug.warn("mediastream.play %w called with Flash-dependent length param: %w", this, length);
}
}
break;
}
// Map symbolic reset values to Flash integers.
switch (reset) {
case true:
case false: {
// The same.
break;
}
case 'queueWithImmediateMessages':
reset = 2;
break;
case 'resetWithImmediateMessages':
reset = 3;
break;
default:
if ($debug) {
Debug.warn("mediastream.play %w called with Flash-dependent length param: %w", length);
}
break;
}
if (this.debug) {
if ($debug) {
Debug.write("mediastream play", this, "_flashstream", this._flashstream, "type", this.type, "url", this.url);
}
}
// unload
if (this._flashstream) {
if (this.paused) {
// unpause
this.setAttribute('paused', false);
return;
} else {
// clear, reset
this._resetStream();
}
}
// Start must be undefined for a live mediastream.
this._basetime = ((start == undefined) || (start < 0)) ? 0 : start;
this.setAttribute("time", 0);
this.setAttribute("progress", 0.0);
// call internal play method after start, length, and reset params
// have been translated into confusing flash player values
this._play(pause, start, length, reset);
</method>
<method name="_play" args="pause, start, length, reset">
var isnew = false;
if (!this._flashstream) {
isnew = true;
this._createStream("_play", [pause, start, length, reset]);
if (!this._flashstream) {
return;
}
}
// note the mode 'playing' means playing, as opposed to recording or
// broadcasting. It also includes the 'paused' state
this.setAttribute("mode", "playing");
if ($debug) {
if (!this._flashstream) {
Debug.warn('mediastream %w unexpected _flashstream=%w',
this, this._flashstream);
}
}
// set up delegate to update the time, progress and fps attributes.
this._activateTimeDel();
//var sname = this._namefromurl(this.url);
var sname = this.url;
//Debug.write("start=", start);
//Debug.write("pause=", pause);
if (pause) {
//Debug.write("mediastream play PAUSE", this, "start", start, "pause", pause, "length", length, "reset", reset);
//seems like overkill, but all of the following seemed to be
//required
this._flashstream.play(sname, start, length, reset);
this.setAttribute("paused", true);
this._flashstream.seek(0);
} else {
//Debug.write("mediastream play PLAY %w sname=%w start=%w length=%w reset=%w ",
// this, sname, start, length, reset);
//this._flashstream.play(sname);
this._flashstream.play(sname, start, length, reset);
this.setAttribute("paused", false);
}
if (this.type == "rtmp") {
this._pendingstreamname = sname;
}
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w play initiated sname=%w"
+" mode=%w", this, sname, this.mode);
}
}
</method>
<method name="_handleAutoplay" args="ignore=null">
//Debug.write("mediastream._handleAutoplay()");
if ((this.url == "") ||
(!this.autoplay)) {
return;
}
this.play(
this.autoplayStart,
this.autoplayPause,
this.autoplayLength,
this.autoplayReset);
</method>
<method name="_activateTimeDel">
//Debug.write("mediastream._activeTimeDel()", this);
if (!this._timedel) {
this._timedel = new LzDelegate(this, "_updateTime");
}
this._timedel.unregisterAll();
this._timedel.register(lz.Idle, "onidle");
</method>
<method name="_deactivateTimeDel">
//Debug.write("mediastream._deactiveTimeDel()", this);
if (this._timedel) {
this._timedel.unregisterAll();
}
</method>
<method name="_updateTime" args="ignore">
//Debug.write("mediastream._updateTime time=%w mode=%w paused=%w",
// this.time, this.mode, this.paused);
/* seems to work better without this
// don't update if new lz.mediastream about to start
if (this._pendingstreamname != "") {
if ($as3) {
// TODO: why doesn't _pendingstreamname get reset?
} else {
return;
}
}
*/
if (!this._flashstream) return;
var time = 0;
var progress = 1.0;
if ($as3) {
var fps = this._flashstream.currentFPS;
} else {
var fps = this._flashstream.currentFps;
}
switch (this.mode) {
case "playing": {
time =
this._flashstream.time + this._basetime;
var bytesTotal = this._flashstream.bytesTotal;
var bytesLoaded = this._flashstream.bytesLoaded;
if ((bytesTotal != null) && (bytesTotal > 0)) {
progress = bytesLoaded / bytesTotal;
}
break;
}
case "recording": {
var time =
((new Date()).getTime() - this._basetime) / 1000;
if (time != this.time) {
this.setAttribute("time", time);
}
break;
}
default: {
break;
}
}
if (time != this.time) {
this.setAttribute("time", time);
}
if (this.progress != progress) {
this.setAttribute("progress", progress);
}
//Debug.write("_updateTime", this, "_flashstream", this._flashstream, "_pendingstreamname", _pendingstreamname);
// Only update in playback mode.
if (fps != this.fps) {
this.setAttribute("fps", fps);
}
// Push totaltime up if time past end
// (because we got the wrong totaltime somehow).
if ((this.totaltime == 0) ||
isNaN(this.totaltime) ||
(this.totaltime < this.time)) {
this.setAttribute("totaltime", this.time);
}
// Keep playing while we're recording,
// or while we're playing,
// or while we're still downloading.
// (So the download progress bar updates while we pause playing.)
if ((this.mode != "recording") &&
(this.mode != "playing") &&
(progress == 1.0)) {
this._deactivateTimeDel();
}
</method>
<method name="_publishSetup">
//Debug.write("_publishSetup", this, this.streamname);
if (this.type != "rtmp") {
if ($debug) {
Debug.warn("in order to record, type must be rtmp %w", this);
}
return;
}
if (this.cam) {
this.setAttribute("mutevideo", false);
}
if (this.mic) {
this.setAttribute("muteaudio", false);
}
if (this.streamname != "") {
// cool; already has a name
} else if (this.url != "") {
this.streamname = this._namefromurl(this.url);
} else {
// TODO? make up temporary name
}
</method>
<method name="broadcast">
if (!this._flashstream) {
this._createStream("broadcast");
}
// rely on callback for as3
if (! this._flashstream) return;
this._publishSetup();
//Debug.write("publish", this.streamname);
this._flashstream.publish(this.streamname);
this.setAttribute("mode", "broadcasting");
</method>
<method name="record">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w record: "+
"fs=%w streamname=%w url=%w",
this, this._flashstream, this.streamname, this.url);
}
}
if (!this._flashstream) {
this._createStream("record");
}
// rely on callback for as3
if (! this._flashstream) return;
this._publishSetup();
//Debug.write("mediastream record", this, "done with setup, streamname", this.streamname);
this._flashstream.publish(this.streamname, "record");
//Debug.write("publish", this.streamname);
this._basetime = (new Date).getTime();
//Debug.write("basetime = ", this._basetime);
this.setAttribute("time", 0);
this.setAttribute("progress", 0.0);
this.setAttribute("mode", "recording");
this._activateTimeDel();
</method>
<method name="pause" args="p=null">
//Debug.write("pause", this, "p", p, "p == null", p == null, "this['paused']", this['paused']);
var val = (p == null) ? !this['paused'] : p;
if (val != this.paused) this.setAttribute("paused", val)
</method>
<method name="stop">
if ($debug) {
if (this.debug) {
Debug.write('mediastream %w stop fs=%w mode=%w',
this, this._flashstream, this.mode);
}
}
if (this.paused) {
// can't be paused and stopped at the same time...
setAttribute('paused', false);
}
if (this._flashstream == null) {
return;
}
switch (this.mode) {
case "recording":
this._deactivateTimeDel();
// fall through to broadcasting
case "broadcasting":
if ($as3) {
this._flashstream.close();
//See this doc for info: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/NetStream.html#close()
//See this doc for info: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/NetStream.html#publish()
} else {
this._flashstream.publish(false);
}
break;
case "playing":
this._flashstream.play(false);
this._deactivateTimeDel();
break;
case "":
// Already stopped.
break;
default:
if ($debug) Debug.warn("bogus mode: " + this.mode);
break;
}
this.setAttribute("time", 0);
this.setAttribute("progress", 0);
this.setAttribute("mode", "");
</method>
<method name="close">
//Debug.write("mediastream.close()");
//Debug.write("FLASHSTREAM CLOSE", this, this._flashstream);
if (this._flashstream == null) {
return;
}
this.stop();
if ($as2) {
this._flashstream.attachVideo(null);
}
this._flashstream.attachAudio(null);
this._flashstream.close();
this._flashstream = null;
//this._flushnc()
</method>
<method name="_findnc">
//Debug.write("_findnc", this, this._nc, this.type, this.url, "isinited", this.isinited);
if (this.type == undefined) return; // called too early
if (this._nc) {
return;
}
//Debug.write('_findnc', this.type);
switch (this.type) {
case "http": {
// keep one of these around for any http mediastream
// we need (weird flash thing that we need a
// null NetConnection)
lz.mediastream._nullnc = new NetConnection();
lz.mediastream._nullnc.connect(null);
this._nc = lz.mediastream._nullnc;
this._srcurl = null;
//Debug.write("_findnc made new _nullnc", this._nc, this._srcurl);
break;
}
case "rtmp": {
//Debug.write("lz.rtmpconnection", lz.rtmpconnection);
if (lz.rtmpconnection == undefined) {
if ($debug) Debug.warn("rtmpconnection must be included for %w", this);
}
// If we don't define our own connection, then use
// the default one (the first rtmpconnection created).
//Debug.write("_findnc type rtmp, rtmpconnection", this.rtmpconnection, "_nc", lz.rtmpconnection.connections._default._nc);
if (! this.rtmp && lz.rtmpconnection.connections) {
this.rtmp = lz.rtmpconnection.connections._default;
}
if (! this.rtmp) {
if ($debug) Debug.warn("No rtmpconnection found for %w.", this);
return
}
// register for connection
new LzDelegate(this, '_handleAutoplay', this.rtmp, 'onconnect');
// register for reconnection
new LzDelegate(this, '_recreateStream', this.rtmp, 'on_nc');
this._nc = this.rtmp._nc;
this._srcurl = this.rtmp.src;
//Debug.write('found rtmp', this._nc, this._srcurl);
break;
}
default: {
if (this.debug) {
if ($debug) Debug.warn(
"unexpected protocol for url: %w %w",
this.url,
this);
}
break;
}
}
</method>
<method name="_recreateStream" args="ignore=null">
this._nc = this.rtmp._nc;
this._flashstream = null;
</method>
<method name="_flushnc">
//Debug.write("mediastream._flushnc()");
if (this._nc == null) {
return;
}
//Debug.write('_flushnc', this, this.type, this._nc);
this._nc = null;
</method>
<method name="_createStream" args="callbackName='', callbackArgs=null">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w type=%w creating internal flash "
+ "stream, _nc=%w _flashstream=%w url=%w callback=%w",
this, this.type, this._nc, this._flashstream, this.url,
callbackName);
}
}
if (!this.url || this.url == '') {
if ($debug) {
if (this.debug) {
Debug.warn( "Can't create mediastream w/ no url: %w %w",
this, arguments.caller);
}
}
return;
}
if (this._flashstream) {
if ($debug) Debug.warn("_flashstream already defined: %w", this._flashstream);
return;
}
if (! this._nc) {
if ($debug) {
// note: null nc is creted when setting the type for 'http'
if (this.type && this.type != 'http') {
Debug.warn("No netconnection defined for %w.", this,
this._nc);
}
}
return;
}
if ($as3) {
if(this._nc.connected) {
_AS3createStream();
} else {
// TODO: why aren't we already connected?
//Debug.warn('Must connect before creating stream', this._nc, this._srcurl, this._nc.connected);
this._nc.addEventListener(NetStatusEvent.NET_STATUS, this._onNetStatusAS3);
this._nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this._onSecurityError);
this._creationCallback = {methodName: callbackName, args: callbackArgs};
setTimeout(this.rtmp._doconnect, 1);
}
} else {
this._flashstream = new NetStream(this._nc);
this._flashstreamSetup( this._flashstream );
}
</method>
<method name="_onSecurityError">
//the following does not compile in swf9 since error is undefined
//not sure where that used to come from
//if ($debug) Debug.warn("mediastream _onSecurityError() " + error);
</method>
<method name="_onAsyncError">
//the following does not compile in swf9 since error is undefined
//not sure where that used to come from
//if ($debug) Debug.warn("mediastream _onAsyncError() " + error);
</method>
<method name="_onNetStatusAS3" args="evt">
if ($debug) {
if (this.debug) Debug.info("mediastream _onNetStatusAS3() " + evt.info.code);
}
if (evt && evt.info && evt.info.code == 'NetConnection.Connect.Success') {
_AS3createStream();
} else {
if (evt && evt.info && evt.info.code) this._onStatus(evt.info);
}
</method>
<method name="_AS3createStream">
var fs = new NetStream(this._nc);
this._flashstreamSetup(fs);
if (this._creationCallback) {
this[this._creationCallback.methodName].apply(this, this._creationCallback.args);
}
</method>
<method name="_flashstreamSetup" args="netstream">
//Debug.debug("_flashstreamSetup netstream=%w", netstream);
this.setAttribute("_flashstream", netstream);
if ($as3) {
this._flashstream.bufferTime = this.buffertime;
} else {
this._flashstream.setBufferTime(this.buffertime);
}
if ($as3) {
this._flashstream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this._onAsyncError);
this._flashstream.addEventListener(NetStatusEvent.NET_STATUS, this._onNetStatusAS3);
var attachPoint = {};
} else {
var attachPoint = this._flashstream;
}
var _this = this;
attachPoint.onStatus = function(info) {
_this._onStatus(info);
};
attachPoint.onCuePoint = function(info) {
_this._onCuePoint(info);
};
attachPoint.onPlayStatus = function(info) {
_this._onPlayStatus(info);
};
attachPoint.onMetaData = function(info) {
_this._onMetaData(info);
};
if ($as3) {
this._flashstream.client = attachPoint;
}
//Debug.debug("_flashstreamSetup end");
</method>
<method name="_onStatus" args="info">
if (! this._flashstream) return;
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w _onStatus %w %w time=%w",
this, info.code, info, this._flashstream.time);
}
}
switch (info.code) {
case "NetStream.Buffer.Empty": {
//var newbuftime = this._flashstream.bufferTime + 1;
//this._flashstream.setBufferTime(newbuftime);
//Debug.write("newbuffertime", newbuftime);
break;
}
case "NetStream.Buffer.Full": {
if (this._pendingstreamname != "") {
this.setAttribute("streamname", this._pendingstreamname);
this._pendingstreamname = "";
}
break;
}
case "NetStream.Play.Start": {
if (this._pendingstreamname != "") {
//v.show(); // FIXME: what is v?
}
this._onStart(info);
break;
}
case "NetStream.Play.Stop": {
// don't call _onStop for rtmp streams because some servers sent this event when they're done streaming (red5, wowza) - see LPP-7708
if (this.type == 'http') this._onStop();
break;
}
case "NetStream.Play.InsufficientBW": {
this._onInsufficientBandwidth(info);
break;
}
case "NetStream.Record.Start": {
this._onStart(info);
break;
}
case "NetStream.Record.Stop": {
this.stop();
break;
}
case "NetStream.Buffer.Flush": {
break;
}
case "NetStream.Publish.Start": {
// Sent when starting recording from camera to server,
// and apparently when we stop as well.
// info.details = first time: null, subsequently: false
// No way to figure out if it's starting or stopping.
break;
}
case "NetStream.Play.UnpublishNotify": {
// Called when stop publishing live video cam. (???)
break;
}
case "NetStream.Unpublish.Success": {
// Sent after you start playing a stream after recording it. (???)
break;
}
case "NetStream.Pause.Notify": {
// Sent after you pause.
break;
}
case "NetStream.Unpause.Notify": {
// Sent after you unpause.
//Debug.write("NetStream.Unpause.Notify");
break;
}
case "NetStream.Play.Reset": {
// Sent after you start playing a stream after recording it. (???)
break;
}
case "NetStream.Seek.Notify": {
// Sent after seeking.
break;
}
default: {
if ($debug) {
if (this.debug) Debug.warn("mediastream _onStatus not handled %w %w %w", this, info.code, info);
}
break;
}
}
</method>
<setter name="buffertime" args="time=0">
if (time < 0) time = 0;
if (time != this.buffertime) {
if (this._flashstream) {
if ($as3) {
this._flashstream.bufferTime = time;
} else {
this._flashstream.setBufferTime(time);
}
}
}
this.buffertime = time;
if (this.onbuffertime.ready) this.onbuffertime.sendEvent(time);
</setter>
<setter name="type" args="newtype">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w set type=%w called by %w",
this, newtype, arguments.caller);
}
}
var old = this.type;
this.type = newtype;
//Debug.write("mediastream set type", this, "old", old, "new", newtype, "_nc", this['_nc'], "isinited", this.isinited);
if ((!this.isinited) ||
(old == newtype)) {
//Debug.write("set type returning because !isinited or same url", this, newtype);
return;
}
this._flushnc();
this._updateUrl();
if (this.ontype.ready) {
this.ontype.sendEvent(this.type);
}
</setter>
<setter name="mode" args="newMode">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w set mode=%w playing=%w paused=%w",
this, newMode, this.playing, this.paused);
}
}
this.mode = newMode;
if (this.onmode.ready) {
this.onmode.sendEvent(newMode);
}
</setter>
<method name="_onCuePoint" args="info">
//Debug.write("mediastream._onCuePoint()");
//Debug.write("ms onCuePoint", this, info);
if (this.oncuepoint) {
this.oncuepoint.sendEvent(info);
}
</method>
<method name="_onStart" args="info">
// TODO: should be conditionally compiled for debug
// but I forget the syntax for that
//Debug.write("mediastream._onstart()");
if (this.onstart) this.onstart.sendEvent(this);
</method>
<method name="_onStop" args="info=null">
//Debug.write("mediastream._onstop before mode=%w",this.mode);
// I don't know why this is sometimes called when
// seeking while paused, but it is
if (this.paused) return;
if (!this.paused) this.setAttribute('paused', true);
if (this.autorewind) {
// TODO: time != totaltime here, so the test failed - seek anyhow.:
// Debug.info('times', this.time == this.totaltime, this.time, this.totaltime);
this.seek(0);
}
if (this.onstop) this.onstop.sendEvent(this);
//Debug.write("mediastream._onstop after mode=%w",this.mode);
</method>
<method name="_onInsufficientBandwidth" args="info">
Debug.write("mediastream.oninsufficientbandwidth()");
if (this.oninsufficientbandwidth) {
this.oninsufficientbandwidth.sendEvent(this);
}
</method>
<method name="_onPlayStatus" args="info">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w onPlayStatus %w %w",
this, info.code, info);
}
}
switch (info.code) {
case "NetStream.Play.Complete": {
// Correct for valid Buffer.Empty.
// I don't understand why it's doing this. -dhopkins
//var newbuftime =
// this._flashstream.bufferTime - 1;
//this._flashstream.setBufferTime(newbuftime);
//Debug.write("newbuffertime=",newbuftime);
this.stop();
break;
}
default: {
if ($debug) {
if (this.debug) {
Debug.warn("mediastream _onPlayStatus not handled: %w %w %w", this, info.code, info);
}
}
break;
}
}
</method>
<method name="_onMetaData" args="info">
//Debug.write("mediastream %w _onMetaData", this);
if ($debug) {
if (this.debug) {
for (var propName in info) {
Debug.write("MetaData: " + propName + " = " + info[propName]);
}
}
}
if (('duration' in info) && this.totaltime !== info.duration) {
//Debug.write("Total play time: ", info.duration);
this.setAttribute("totaltime", info.duration);
}
if (this.onmetadata.ready) this.onmetadata.sendEvent(info);
</method>
<setter name="paused" args="paused">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w set paused=%w",
this, paused);
}
}
if ((this.mode != "playing") || !this._flashstream) {
if (paused) {
this.play('either', true);
}
return;
}
if ($as3) {
if (paused) {
this._flashstream.pause();
} else {
this._flashstream.resume();
}
} else {
this._flashstream.pause(paused);
}
this.paused = paused;
if (this['onpaused']) {
this.onpaused.sendEvent(paused);
}
// Stop the timer if we're paused
if (this.paused) {
this._deactivateTimeDel();
} else {
this._activateTimeDel();
}
//Debug.write("PAUSE", "after playing", this.playing);
</setter>
<method name="seek" args="t">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w seek %w",
this, t);
}
}
if (url == "") return;
if (!this._flashstream) {
this._createStream("seek", [t]);
}
if (this._flashstream) {
this._flashstream.seek(t);
// DON'T call _updateTime since the flashstream's time
// will be wrong for a while and later it will show the closest
// keyframe's time, which is arguably correct but screws up
// the displays of scrubbers and whatnot
this.setAttribute('time', t);
if (!this.playing) {
// just in case we have never displayed the video
this.pause(true);
}
}
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w seek(%w %w) fs=%w",
this, typeof(t), t, this._flashstream);
}
}
</method>
<method name="init">
this.paused = false;
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w init immediateparent=%w, url=%w" +
"called by %w",
this, this.immediateparent, url, arguments.caller);
}
}
super.init();
// check for the existence of immediateparent.videoview
if (lz['videoview'] && immediateparent instanceof lz.videoview) {
immediateparent.setAttribute('stream', this);
}
if (this.url != "") {
this.setAttribute('url', this.url);
}
</method>
<method name="_namefromurl" args="fromurl">
var sname = fromurl;
//Debug.write("sname=", sname, "suffix=", sname.substr(-4));
// FIXME: Compare file name suffix ignoring case.
if ((this.type == "rtmp") &&
(sname.substr(-4) == ".flv")) {
sname = sname.slice(0,-4);
}
//Debug.write("mediastream._namefromurl(%w) %w", fromurl, sname);
return sname;
</method>
<setter name="url" args="newurl">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w set url=%w called by %w",
this, newurl, arguments.caller);
}
}
var old = this["url"];
//Debug.write("mediastream set url", this, "old", old, "new", newurl, "_nc", this['_nc'], "isinited", this.isinited);
this.url = newurl;
this.setAttribute("streamname", "");
if ((!this.isinited)) {
//Debug.write("set url returning because !isinited", this, newurl);
//TODO: find out why we stop here on construct...
return;
}
this._updateUrl();
if (this.url != "") { // changing the url
this._handleAutoplay();
}
if (this.onurl.ready) {
//Debug.write("mediastream.set url() / sending onurl event!");
this.onurl.sendEvent(this.url);
}
</setter>
<method name="_updateUrl">
// Debug.write(" _updateUrl", this, this.type, this.url, "isinited", this.isinited);
this._resetStream();
this._findnc();
if ((this.type == "rtmp") &&
(this.url != null) &&
(this.url != "")) {
//this breaks red5 and depends on Flash Media Server - see LPP-4785
/** TODO: when to do this?
// rtmp server appends the .flv (so we need to remove it)
var sname = this._namefromurl(this.url);
// call function in server-side main.asc
var t = this; // for use in closure
this.onResult = function(streamLength) {
//_root.Debug.write("onresult=", streamLength);
t.setAttribute("totaltime", streamLength || 0);
};
*/
}
</method>
<setter name="cam" args="cam">
this.cam = cam;
if (this["oncam"]) this.oncam.sendEvent();
</setter>
<setter name="mic" args="mic">
this.mic = mic;
if (this["onmic"]) this.onmic.sendEvent();
</setter>
<setter name="muteaudio" args="muteaudio">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w set muteaudio=%w called by %w",
this, muteaudio, arguments.caller);
}
}
this.muteaudio = muteaudio;
if (!this.mic) return;
if (!this._flashstream) return;
this._setupStreamAudio();
if (this["onmuteaudio"]) this.onmuteaudio.sendEvent();
</setter>
<setter name="mutevideo" args="mutevideo">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w set mutevideo=%w called by %w",
this, mutevideo, arguments.caller);
}
}
this.mutevideo = mutevideo;
if (!this.cam) return;
if (!this._flashstream) return;
this._setupStreamVideo();
if (this["onmutevideo"]) this.onmutevideo.sendEvent();
</setter>
<method name="_setupStreamAudio">
if ($as2) {
var noaudioobject = false;
} else {
// attachAudio() requires a Microphone object in AS3 - see
// http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/net/NetStream.html#attachAudio%28%29
var noaudioobject = null;
}
this._flashstream.attachAudio(this.muteaudio ? noaudioobject : this.mic._dev);
</method>
<method name="_setupStreamVideo">
if ($debug) {
if (this.debug) {
Debug.write("mediastream %w _setupStreamVideo: " +
"fs=%w, cam=%w, mutevideo=%w",
this, this._flashstream, this.cam, this.mutevideo);
}
}
if ($as3) {
this._flashstream.attachCamera(this.mutevideo ? null : this.cam._dev);
} else {
this._flashstream.attachVideo(this.mutevideo ? false : this.cam._dev);
}
</method>
</class>
</library>