什麼是Flash Media Server ?
Flash大家庭裏的一員,這個東東以前叫Flash Communication Server,傳說中的FCS就是這個,現在改叫FMS了...
不見不知道哦,一見真可怕,adobe還有這麼cool的東東,自從見了她,讓我做些小東東的興趣全沒了,一心想研究這個
這東東能做什麼?
視頻錄製啊,flash聊天室啊,在線視頻會議啊啊, 網絡遊戲?
不管怎樣先安個試試吧
先到這裏下載免費的開發者版本吧
http://www.macromedia.com/software/flashmediaserver/
然後安裝,安裝時記得用戶名和密碼不要瞎填自己要記住,如果你已經瞎填了那就到 安裝目錄下\conf\fms.ini 裏找吧
偶裝到了c盤,找到目錄
C:\Program Files\Macromedia\Flash Media Server 2
先要打開服務器哦
你在本機裝的fms,本機就是服務器了哦!記得現在你的機器既是客戶端又是服務端哦
開始===程序===Macromedia===Flash Media Server 2
有兩個start****,都要打開,關時候兩個都要關,如果你怕麻煩直接找tool文件夾裏的批處理文件StartServerService.bat吧,雙擊他,他會幫你搞定地,想關就找StopServerService.bat。~
applications文件夾
你可以在裏邊建一個文件夾例如叫 FirstApp,這就建了一個Application,以後所有此項目服務器端的flv文件啊,共享文件啊都會在這裏邊,有時服務器端需要寫程序的時候裏邊會有個main.asc 文件,這個就是服務器端程序,服務器端程序目前只支持as1寫,是在服務器上執行的,你也可以用trace調試,怎麼trace管理服務器時候你會看到,你可能會建若干個app,在一臺服務器上同時運行,比如錄象的app,聊天室的app。。。這些所有的app都通過fms自帶的fms2_console.swf管理,現在就去看看如何管理服務器吧!
管理服務器~
服務器打開後就要管理了哦,點開fms2_console.swf,別看他只是個swf,後臺管理就靠他了,輸入你安裝時候的密碼和用戶,服務器地址寫 localhost 就好看到了吧,熟悉熟悉他吧
以後我們寫程序最常用的就是這個View Applications ,每當有客戶端連接服務器時,左邊就會列出連接的是哪個app,有多少連接 下圖爲連接applications文件夾下的bs文件夾(bs文件夾,因爲每個文件夾對應一個app,就是bs app),連接數爲1,458是實例名(實例名默認爲 _definst_ ,每個文件夾可以有若干實例,互相不影響,這個特性可以用來做聊天是的房間,以後再說)
選中某個app後,或者客戶端有連接,會看到當前打開的app的狀態,這個
Live Log 服務器端的trace就這裏看了 ,右邊依次是客戶端情況 , 共享對象,流,執行的情況(佔內存,cpu等),後邊兩個小按鈕,調試時候常用哦,reload和unload!
每當服務器端main.asc修改後一定記得reload或者unload一下,否則不會生效,unload會把窗口關閉,有客戶端連的時候還會自動打開
總有人告訴我,他的fms經常會出現詭異現象,比如連接不上,代碼已經刪了還會執行,一生氣連文件夾都刪了,還會執行,懷疑是自己的rp有問題。。
那不是rp問題,記住出現問題就reload !實在不行就去tools文件夾點StopServerService.bat
conf文件夾
還有重要的是conf文件夾了,裏邊是一些服務器端的配置文件,以後可能會用,先不用動。。。。
自此,安裝部分結束,go on...
有一種協議叫rtmp
客戶端和服務器端通信是使用協議rtmp的
現在在服務器端applications文件夾(當然偶的客戶端和服務器端是一臺機器了)裏建個test1文件夾,你的地址就爲
rtmp:/test1 或者 rtmp://localhost/test1
注意兩個地址中的 "/ "符號
打開flash
與服務器通信首先要建個NetConnection()
nc = new NetConnection();
連接
nc.connect("rtmp://localhost/test1");
怎麼知道連沒連上呢?順利連接服務器後會觸發一個onStatus事件,自己trace一下info.code
nc.onStatus = function(info) {
//trace(info)
//trace(info.code)
for (i in info) {
trace(i+": "+info[i]);
}
};
完整代碼:
nc = new NetConnection();
nc.onStatus = function(info) {
trace(info.code);
if (info.code == "NetConnection.Connect.Success") {
trace("接通");
}
};
nc.connect("rtmp://localhost/test1");
注意:默認情況下服務器是允許你連接的,但只是默認,如果服務器拒絕你連接的話,上述代碼就不好用了。怎麼回事?我們看看連接的過程吧
連接過程
每當客戶端試圖連接服務器,一個NetConnection.connect(),服務器將會調用application.onConnect 來鑑定是不是允許客戶端連接,onConnect()方法返回null 或不返回則將進入未決狀態,直到onConnect方法中返回true或執行acceptConnection(client)則允許,返回false或執行rejectConnection(client)則拒絕,如圖(從左往右看)
服務器文件是以.asc形式存在的,可以在test1文件夾裏建一個main.asc
application.onConnect=function(client){
this.rejectConnection(client);
//this.acceptConnection(client)
}
這樣就拒絕連接了,動手試試,別忘了,服務器端改動的話,別忘了到fms2_console.swf去reload !不知道按哪個的到上邊找,每當有客戶端連接,那個reload按鈕的界面就會出來哦。
檢查是否uri錯誤
如果你的rtmp地址是從其他什麼地方傳過來的,可以順便檢查一下rtmp是否錯誤,下邊代碼如果地址是錯誤的就會trace出來
mync = new NetConnection();
mync.onStatus = function(info) {
if (info.code == "NetConnection.Connect.Success") {
trace("連接成功");
}
};
//正確的uri
//uri = "rtmp://localhost/connect";
//錯誤的uri
uri = "rtmpppppp://localhost/connect";
if (mync.connect(uri, "N神")) {
trace("嘗試連接服務器中。。");
} else {
trace("沒有嘗試連接服務器~是uri錯誤???");
}
ok 了,現在我們深入一點點。。看看連接上的一些細節問題
info.code:
連接後info.code會告訴你連接的狀態,上邊看的都是NetConnection.Connect.Success, 還有一些其他值,和這些值是什麼意思,自己看看。
值得注意的是。NetConnection.Connect.Rejected,收到這條消息的時候說明服務器端拒絕了你,接着馬上你會收到另一條,NetConnection.Connect.Closed,連接就關閉了~~~
mync = new NetConnection();
mync.onStatus = function(info) {
switch (info.code) {
case "NetConnection.Connect.Success" :
trace("連接成功");
break;
case "NetConnection.Connect.Failed" :
//關掉服務器的情況
trace("嘗試連接失敗,服務器有可能掛掉了 -_-b");
break;
case "NetConnection.Connect.Rejected" :
//注意這裏,服務器拒絕你的情況,如果遭到拒絕,將會調用兩次mync.onStatus,
//第一次"NetConnection.Connect.Rejected"第2次"NetConnection.Connect.Closed"
trace("遭到服務器拒絕");
trace("服務器返回信息:"+info.application.msg);
break;
case "NetConnection.Connect.Closed" :
trace("連接關閉");
break;
}
};
mync.connect("rtmp://localhost/connect", "N神");
//mync.connect("rtmp://localhost/connect","小新")
服務器端拒絕連接?好象見過。。。回頭找找。。。。。。。。哦在這裏
application.onConnect = function(client) {
this.rejectConnection(client);
}
我不能所有人都拒絕了。。我要把討厭的人拒絕了。。。
傳給服務器一個人名~~
mync.connect("rtmp://localhost/connect", "N神");
服務器看看是不是討厭的人。。
application.onConnect = function(client, name) {
trace(name);
if (name == "N神") {
//拒絕連接,並返回個錯誤對象{msg:"服務器不想"+name+"進去,哈哈~"},包含錯誤消息
application.rejectConnection(client, {msg:"服務器不想"+name+"進去,哈哈~"});
} else {
application.acceptConnection(client);
//成功不能返回客戶端信息
}
};
看客戶端的代碼。。
case "NetConnection.Connect.Rejected" :
//注意這裏,服務器拒絕你的情況,如果遭到拒絕,將會調用兩次mync.onStatus,
//第一次"NetConnection.Connect.Rejected"第2次"NetConnection.Connect.Closed"
trace("遭到服務器拒絕");
trace("服務器返回信息:"+info.application.msg);
break;
遭到服務器拒絕後會trace出服務器返回的錯誤消息,這是一個最基礎的與服務器交互的例子,以後還會有很多滴
下邊進入新一層次。。。
視頻,流
這個比較重要,但超簡單,網上播放電影,在線錄製,在線播放,視頻會議,視頻電話,全靠他了 ,下邊我們先做一個最簡單 錄製和播放
錄製視頻
打開flash,新建一個fla,Ctrl + L 打開library,右鍵新建視頻,確定。
拉到舞臺上起個名叫my_video
第一幀開始加代碼
//從麥和設像頭顯示視頻顯示在my_video上
my_video.attachVideo(Camera.get());
my_video.attachAudio(Microphone.get());
//像以前一樣連接
nc = new NetConnection();
nc.connect("rtmp://localhost/aaaa"); //注意這裏,Applications文件夾裏要有aaaa文件夾哦!
//可以理解爲在nc連接上綁一個流
nsOut = new NetStream(nc);
//在流上加麥克風和視頻頭
nsOut.attachVideo(Camera.get());
nsOut.attachAudio(Microphone.get());
//發佈 2.flv
nsOut.publish("2", "record");
第一個參數是文件名,後一個參數要"record"纔是錄製
把fla發佈一下, 錄一會兒,把視頻關掉,打開你的
叉盤:\Program Files\Macromedia\Flash Media Server 2\applications\aaaa\
是不是多了個streams\_definst_
打開C:\Program Files\Macromedia\Flash Media Server 2\applications\aaaa\streams\_definst_
看見2.flv了吧。。
這裏下載原文件 : http://www.nshen.net/blog/attachments/200601/25_163617_c1.fla
播放flv
用fms播放的flv目前是無法下載的,這可以保護你的版權 :)
打開flash,新建一個fla ,Ctrl + L 打開library,右鍵新建視頻,確定。
拉到舞臺上,這回起個名叫view ,我們來播放你剛纔錄的那個視頻
nc = new NetConnection();
nc.connect("rtmp://localhost/aaaa");
res = new NetStream(nc);
//view元件要加載res流
view.attachVideo(res);
view.attachAudio(res);
//播放
res.play("2");
原文件 : http://www.nshen.net/blog/attachments/200602/13_223604_p1.fla
現場流
上邊做的都是先錄製好了視頻,然後才播放,網上的實時視頻會議,視頻電話是怎麼做的呢?總不能先錄好再播放吧?
這要用到現場流,現場流是指你連接到服務器後,你在發佈的同時,其他人就可以實時的看到你
很難嗎?看看吧,把上邊錄製視頻的例子拿下來
nsOut.publish("2", "record"); 這句改成 nsOut.publish("2", "live");
把"record" 改成"live"後,就不會生成flv了,取而代之的是一個看不到的實時的視頻流
ok 了,發佈,這就是直播端了,同時再發布上邊那個播放端,已經可以實時看見你了吧。現在你是用本機測試,等你有了服務器。其他人也能同時看見你了哦
到這裏你已經可以自己做一個網頁上的直播了,發佈端不要讓別人看到,讓別人看你的播放端就好了 :) 至於爲什麼要用兩個swf,因爲目前爲止你還不知道怎麼樣跟服務器之間傳遞消息,這樣做可以避免這些東西,等你把後邊的東西全都學完就可以在一個swf裏,寫個視頻會議之類的東東了
遠程共享
遠程共享?
共享的概念就是讓每個連接到服務器的swf都能實時的得到服務器端共享的數據。
一個人更改了這些數據,其他人都會看得到通知。可以想象聊天室裏的發言,一個人發了以後其他人都可以看到。
共享對象
共享對象,說英文大概你比較熟ha~ SharedObject, 恩flash中有兩種sharedObject,local sharedobject (LSO) 和 remote sharedobject (RSO),也就是本地共享和遠程共享,偶們討論遠程的,不過之前你最好先去了解了解本地的,對你有好處...
RSO在服務器端是以文件形式存儲的,擴展名是.fso,爲什麼不是.rso?....我也想問呢- -b
代碼
初始化RSO需要先與服務器建立一個連接,續上節 ,我們先與服務器建立一個連接
//初始化遠程共享要利用nc通道
var myNC = new NetConnection();
myNC.onStatus = function(info) {
if (info.code == "NetConnection.Connect.Success") {
//成功則利用此nc初始化rso
initRSO(this);
}
};
跟以前的代碼一樣,只是連接成功後多了一個initRSO()函數,看不懂的回去重頭再看一下。。。
下邊是initRSO了,跟連接結構差不多
function initRSO(NC) {
//在服務器上建立myRSO.fso文件,第2個參數指定nc通道,第3個指定文件在服務器上持久保留,即使服務器重啓了,還是有
my_rso = SharedObject.getRemote("myRSO", NC.uri, true);
my_rso.onSync = function(list) {
//list 是一個對象數組 ,類似這種[{name:"x",code:"success"},{name:"y",code:"success"}] ,下邊會詳細講
//初始成功
};
my_rso.connect(NC); //連接
}
瞭解了吧,看一個完整的例子
畫一個mc起名叫mc,在第一幀上寫代碼,
//初始化遠程共享要利用nc通道
var myNC = new NetConnection();
myNC.onStatus = function(info) {
if (info.code == "NetConnection.Connect.Success") {
//成功則利用此nc初始化rso
initRSO(this);
}
};
myNC.connect("rtmp://localhost/test1"); //不會不知道要建test1文件夾吧
function initRSO(NC) {
my_rso = SharedObject.getRemote("myRSO", NC.uri, true);
//onSync是回調函數,每次服務器端so數據有改變,這裏都會有反映!這裏的意思每當有人按鼠標,這裏都會有反映,我們讀取so的data下的值就可以了
my_rso.onSync = function() {
mc._x=this.data.x
mc._y=this.data.y
};
my_rso.connect(NC);
}
onMouseDown = function () {
//改變so的數據
my_rso.data.x = _root._xmouse
my_rso.data.y = _root._ymouse
};
然後發佈設置中設置只允許網絡,發佈看看
現在你可以開多個播放器窗口,點其中一個,看看其他的窗口變不變
源文件: http://www.nshen.net/blog/attachments/200601/11_145320_test3.fla
連接流程
再寫一個,看起來很像在做網遊~
mync = new NetConnection();
mync.onStatus = function(info) {
if (info.code == "NetConnection.Connect.Success") {
initRSO();
}
if (info.code == "NetConnection.Connect.Closed") {
trace("關閉");
}
};
function initRSO() {
my_RSO = SharedObject.getRemote("myRSO", mync.uri, true);
trace(my_RSO);
my_RSO.onSync = function() {
mc._x = this.data.hero.x;
};
my_RSO.connect(mync);
}
mync.connect("rtmp:/my_app/test1");
mc.onEnterFrame = function() {
my_RSO.data.hero.x = this._x;
if (Key.isDown(Key.LEFT)) {
this._x -= 5;
}
if (Key.isDown(Key.RIGHT)) {
this._x += 5;
}
};
寫個簡單的聊天室
很簡單的東西,基本上就是共享對象的運用,沒有用到服務器端,大型聊天室可能不會這麼做,這個只適用於初學者 :/
註釋很詳細,不說多了,可以直接下載原文件
http://www.nshen.net/blog/attachments/200602/smallchat.fla
代碼:
//用戶名
myname="遊客"
//建立連接
var myNC = new NetConnection();
myNC.connect("rtmp://localhost/smallchat");
//搞到rso
Talk_SO = SharedObject.getRemote("Talk", myNC.uri, false);
Talk_SO.onSync = function() {
//先把聊天文本框清空
remoteText.text = "";
//把聊天列表顯示出來,talklist的格式就是[誰誰說:啊啊啊,誰誰誰說:2222]
var t = this.data.talklist;
for (var i = 0; i<t.length; i++) {
writeln(t[i]);
}
};
Talk_SO.connect(myNC);
//發消息函數
function post() {
//如果不存在talklist就建一個,這裏沒用server端,是個技巧
if (Talk_SO.data.talklist[0] == undefined) {
Talk_SO.data.talklist = [];
}
//限制數組長度,是個隊列。保證裏邊有5條消息,當然也可以更多,但如果沒有限制,flash會垮的
if (Talk_SO.data.talklist.length>=5) {
Talk_SO.data.talklist.shift();
}
//把消息裝到so裏
Talk_SO.data.talklist.push(myname+"說:"+meText.text);
meText.text = "";
}
//文字顯示,換行
function writeln(msg) {
remoteText.text += msg+"\n";
remoteText.vPosition =remoteText.maxVPosition
}
//-----------------------------------------------
Btn.onRelease = function() {
post();
};
this.onKeyDown = function() {
if (Key.isDown(Key.ENTER)) {
post();
}
};
Key.addListener(this);
深入onSync
onSync有個list參數,這個開始有些難度了。不想動腦的可以跳過沒影響,只是以後寫出的程序效率會低點 :(
看代碼:
my_rso = SharedObject.getRemote("myRSO", NC.uri, true);
my_rso.onSync = function(list) {//.......};
my_rso.connect(NC); //連接
在onSync回調中我們可以知道我們的my_rso被改變了,但my_rso裏具體什麼改變了呢? 我們就要分析這個 list 參數 了
list參數其實是一個對象數組 ,首先它是一個數組,裏邊裝了很多對象(Object),每一個對象都包括了SharedObject中一個插槽(slot)的改動信息。我暫時給他起名叫插槽信息對象。。。這名字太猥褻了。。但我就這麼叫了。。
插槽信息對象包含兩個屬性,name 和 code,偶爾還會有個oldValue?我不太常用,不說它
name 描述被改變的屬性名
code 描述該屬性的改變方式 ,有可能爲以下幾種值:"success" , "change" , "delete" , "reject" , "clear" ,具體含義後邊說
說白了這個插槽信息對象大概就是這麼個樣子:
{name:"x",code:"success"}
表示x屬性被修改成功
要得到這些插槽信息對象就要for in 這個list參數
for (var i in list) {
list[i] 就是插槽信息對象
}
要分析具體so哪改變了,就是分析list[i],比如
if(list[i].code=="change") trace("list[i].name"+被+"change了")
if(list[i].code=="delete") trace("list[i].name"+被+"delete")
“change”是啥?“delete”是啥?
"success" , "change" , "delete" , "reject" , "clear" 具體含義:
success : 表示當前影片修改so的插槽獲得了成功
change : 表示so的插槽被別人修改,或填加
也就是說,你修改so的某個屬性成功了會收到 "success" ,與此同時其他影片會收到 "change"
reject : 拒絕修改
例如發生在兩個或多個客戶端同時要修改一個so的插槽,這時候fms會只讓一個client修改,並返回"success" 其他的會收到"reject"
delete , clear : 這個好理解,一個是刪除,一個是清空,看例子:
比如服務器端刪除某個so
so = SharedObject.get("某個so");
so.lock( );
var names = so.getPropertyNames( );
for (i in names) {
so.setProperty(names[i], null);
}
so.unlock( );
這樣client端會收到 若干個插槽信息對象,所有的code都爲"delete",表示若干個item被刪除
然而這樣:
so = SharedObject.get("某個so");
so.clear( );
client端就只會收到一個插槽信息對象,code屬性爲“clear”。
client端與server端直接交互
看完了SO,看一下client與server端如何直接進行交互的
原文件在這裏:
http://www.nshen.net/blog/attachments/200602/25_152648_csc.rar
1. 客戶端呼叫服務器
fla:
//客戶端呼叫server端msgfromclient函數,並將返回值trace出來
mync = new NetConnection();
mync.connect("rtmp://localhost/connect");
//返回值接收對象
var resObj = new Object();
resObj.onResult = function(val):Void {
trace("val"+val);
};
/*
我們用mync去call服務器端的msgfromclient函數,resObj是返回接收對象,當服務器有返回值後,會自動直接調用這個對象的onResult處理函數,後邊可以傳遞給server無數個參數,這裏只傳一個字符串
*/
mync.call("msgfromclient", resObj, "第一個call");
服務器端代碼是放在main.asc裏的,你可以到你的application下的connect目錄下建一個main.asc,寫代碼
main.asc:
//要把函數定義到Client上!!
application.onConnect = function(client) {
/* 在這裏定義也可以,在Client.prototype裏定義也是可以的
client.msgfromclient=function(what){
trace(what+"進來了")
var aa="呼叫成功並返回結果"
return aa
}
*/
application.acceptConnection(client);
};
Client.prototype.msgfromclient=function(what){
trace(what+"進來了")
var aa="呼叫成功並返回結果"
return aa
}
現在去試一下吧。。。成功了的話,再繼續.......
2. 服務器端呼叫指定的客戶端
fla:
//server呼叫client端
//要把函數定義到nc上!!
//
mync = new NetConnection();
mync.onStatus = function(info) {
if (info.code == "NetConnection.Connect.Success") {
trace("連接成功");
}
};
mync.connect("rtmp://localhost/connect");
mync.msgfromserver = function(msg) {
trace(msg);
};
main.asc:
application.onConnect = function(client) {
application.acceptConnection(client);
//這裏呼叫剛連線成功的客戶
//跟client呼叫server基本一樣,服務器一般很少讓client端返回值所以第2個參數設爲null
client.call("msgfromserver",null,"服務器叫你啊")
};
3. 服務器端呼叫所有的客戶端(廣播)
有些時候需要服務器廣播數據給所有連接上的客戶端,這裏就用到了廣播的概念
廣播其實SharedObject的時候已經講過了一種實現,就是把數據放到remote SharedObject中,當數據改變了,自然所有客戶端都會onSync
這裏再講一種用call來實現的:
下邊是很常見的一個情況,當某人下線了的時候要通知所有客戶端,某某已經下線了
server端:
application.onDisconnect=function(newClient){
//遍歷客戶端列表,分別call他們
for(var i=0;i<application.clients.length;i++) {
application.clients[i].call("client_fun",null,sendvar);
}
}
Client端:
nc.client_fun=function(myvar){....... }
這個自己完善一下吧,這裏就不貼fla了
還有:
關於廣播,不只有服務器端廣播給所有客戶,還有可能某一個客戶端對所有客戶端直接進行廣播,當然上邊的例子你如果都看懂了的話,你已經可以自己做某一個客戶端對所有客戶端的廣播了。怎麼做?
第1步 某一個客戶端呼叫服務器
第2步 服務器廣播給所有客戶端
這樣就形成了,某客戶端對所有客戶端的廣播,當然如果你能細心的耐心的看看幫助的話,你會發現Shared Object 和 NetStream都有send方法就是做這件事的,而且更爲簡潔,服務端不用寫代碼 :)
好了,看到這裏,fms常用的大部分概念都說到了,這個教程也就基本結束了,想學更多的,你可能需要多翻翻手冊,多找找教程,英文有不少很好的教程進階,下邊我也會貼些資源。
其他需要注意的問題:
* 中文編碼:
有些時候我們用flash去讀取外部的php,asp.....文件裏的中文顯示在flash裏會出現亂碼的情況,爲了解決在flash裏顯示中文很多教程裏通常都直接加了一句System.useCodepage=true
問題就在這,顯示不了外部中文是因爲flash內默認用Unicode編碼,外部的文件大多都是gb2312,加上這句System.useCodepage=true代表強制flash使用系統默認的gb2312,這樣flash就顯示正確了,但fms服務器端默認也是用unicode的,這樣客戶端跟服務器端不同編碼有時就會出錯了,搜了一下server字典好象沒有System.useCodepage=true了。。。所以解決辦法就是去掉System.useCodepage=true,在外部php或asp中把編碼轉成utf-8,至於怎麼轉,不知道,問你的asp或php程序員吧 ,另外不要用記事本編輯你的asc文件。。即使編輯最後要一定另存爲utf-8格式。
* 判斷影片播放結束
ns.onStatus=function(info){
if(info.code=="NetStream.Play.Stop")trace("結束")
}
乍看好象沒錯,但是如果設置了緩衝以後(setBufferTime)就不好用了,仔細研究了一下原因4這樣的
監視onStatus(info) ,info.code:
開始播放
NetStream.Play.Start (其實還沒播放)
然後緩衝(根據setBufferTime設置的秒數緩。。)
NetStream.Buffer.Full (緩衝裝滿了,這纔開始播放)
然後播放完了
NetStream.Play.Stop (其實還沒播放完)
注意了,然後還要播放緩衝 - -b
NetStream.Buffer.Empty (緩衝空了,這才播放完了。。)
羣裏的kinglong兄比較聰明~,先Stop的時候做個記號,然後再滿足Empty纔算播放完,也就是兩個條件,因爲網速慢也會Empty。。。好辦法
但我看了一下幫助,好象有一個專門的事件通知播放結束
ns.onPlayStatus=function(info){
if(info.code=="NetStream.Play.Complete")trace("感謝觀看幫助")
}
* 防火牆,端口
默認安裝的話默認端口是1935,管理是1111端口,記得防火牆要把1935和1111端口打開。