史上第一个Flash P2P源代码来啦!


2008-12-17 05:27




 

经过两天两夜的艰苦努力,史上第一个Flash P2P源代码终于被我老虫搞出来啦!

先看效果图:

再来看使用方法:

在A、B两台具有静态IP的机器上打开本页后,程序首先生成一个随机的用户名myName并自动连接到Adobe官方的stratus服务器,连接成功后,程序会自动获取一个myID号。将A中的myName和myID复制粘贴到B中的oppName和oppID中,单击B中的Call按钮呼叫A,当A中有呼叫的提示信息时,在A中单击Accept按钮,这样P2P连接就建立了!P2P连接建立后,可以播放对方视频,可以进行文本聊天。

通过该示例你可以:

1、了解如何使用新的RTMFP协议连接到远程服务器。

2、了解如何建立P2P连接。

3、了解如何发布和接收P2P流。

4、了解如何进行文本聊天。

已知问题:

1、只能在有静态IP的局域网内使用,广域网的动态分配的IP不行(后经测试,是可以在广域网使用的!)。

2、在进行P2P呼叫的时候速度慢,即使是在同一个局域网内。

SWF文件在下面,你可以将它另存到桌面上使用,要注意允许SWF访问网络及相关的安全设置:

 

源代码如下:

package {
import flash.display.MovieClip;
import fl.managers.StyleManager;
import flash.text.TextFormat;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.net.ObjectEncoding;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.net.URLRequestHeader;
import flash.net.URLVariables;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.events.AsyncErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.events.NetStatusEvent;
import flash.media.SoundTransform;
import flash.media.Camera;
import flash.media.Microphone;
public class p2p extends MovieClip {
   private var fmsPath:String;
   private var myNC:NetConnection;
   private var controlStream:NetStream;
   private var outgoingStream:NetStream;
   private var incomingStream:NetStream;
   private var listenerStream:NetStream;
   private var yourName:String;
   private var yourID:String;
   private var oppName:String;
   private var oppID:String;
   private var WebServiceUrl:String;
   //正式开始喽
   public function p2p() {
    setCommonStyle();
    init();
   }
   private function setCommonStyle() {
    //设置所有组件的样式
    var myTF:TextFormat=new TextFormat ;
    myTF.size=12;
    StyleManager.setStyle("textFormat",myTF);
   }
   //初始化工作
   private function init() {
    fmsPath="rtmfp://stratus.adobe.com/HawkPrerelease-4e4efa13755c/FMSer.cn";
    WebServiceUrl="http://76.74.170.61/cgi-bin/reg";
    myNC=new NetConnection();
    myNC.client=this;
    myNC.objectEncoding=ObjectEncoding.AMF3;
    myNC.addEventListener(NetStatusEvent.NET_STATUS,netStatus);
    myNC.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityError);
    myNC.addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncError);
    //开始连接服务器
    myNC.connect(fmsPath);
    //随机生成用户名
    myNameTxt.text="FMSer"+int(Math.random()*100);
    sendBtn.addEventListener(MouseEvent.CLICK,sendChatMsg);
   }   private function asyncError(e:AsyncErrorEvent) {
   }
   private function securityError(e:SecurityErrorEvent) {
   }
   //连接功能后将自己的用户名和ID传给WEB服务器暂存
   private function netStatus(e:NetStatusEvent) {
    switch (e.info.code) {
     case "NetConnection.Connect.Success" :
      trace("连接成功!");
      myIDTxt.text=myNC.nearID;
      callWebService();
      break;
     case "NetConnection.Connect.Failed" :
      trace("连接失败!");
      break;
     case "NetConnection.Connect.Rejected" :
      trace("连接失败!");
      break;
     case "NetConnection.Connect.Closed" :
      trace("连接中断!");
      break;
    }   }
   //完成用户信息提交工作
   private function callWebService() {
    var urlLoader:URLLoader = new URLLoader();
    urlLoader.addEventListener(Event.COMPLETE, completeHandler);
    urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioerrorHandler);
    var urlRequest:URLRequest=new URLRequest(WebServiceUrl);
    var parameter:URLVariables=new URLVariables ;
    parameter.username=myNameTxt.text;
    parameter.identity=myIDTxt.text;
    urlRequest.data=parameter;
    urlLoader.load(urlRequest);
   }
   //准备呼叫和被呼叫
   private function completeHandler(e:Event) {
    callBtn.addEventListener(MouseEvent.CLICK,startCall);
    completeRegistration();
   }
   private function ioerrorHandler(e:IOErrorEvent) {
   }
   //开始呼叫
   private function startCall(e:MouseEvent) {
    oppName=oppNameTxt.text;
    oppID=oppIDTxt.text;
    placeCall(oppName,oppID);
   }
   //呼叫主函数
   private function placeCall(tmpOppName:String,tmpOppID:String) {
    msgTxt.text="正在呼叫:"+tmpOppName+"...";
    //尝试播放对方视频
    controlStream=new NetStream(myNC,tmpOppID);
    controlStream.addEventListener(NetStatusEvent.NET_STATUS,controlHandler);
    controlStream.play("control" +tmpOppName);
    //对外发布点对点视频
    outgoingStream=new NetStream(myNC,NetStream.DIRECT_CONNECTIONS);
    outgoingStream.addEventListener(NetStatusEvent.NET_STATUS,outgoingStreamHandler);
    outgoingStream.publish("media-caller");
    var o:* = new Object();
    o.onPeerConnect =function (tmpNS:NetStream){
    msgTxt.text="正在建立P2P连接..."
    };
    outgoingStream.client=o;
    startAudio();
    startVideo();
    //接收来自外部的点对点视频
    incomingStream=new NetStream(myNC,tmpOppID);
    incomingStream.addEventListener(NetStatusEvent.NET_STATUS,incomingStreamHandler);
    incomingStream.play("media-callee");
    var st:* =new SoundTransform(50);
    incomingStream.soundTransform=st;
    //被呼叫方接受连接时触发该事件
    var i:* = new Object();
    i.onCallAccepted =function (tmpOppName:String){    
    msgTxt.text=tmpOppName+"已经接受了你的呼叫..."
    };
    //被呼叫方接受连接时触发该事件
    i.onIm = function (userName:String,chatMsg:String){
    chatContent.text =chatContent.text + (userName+ ": " + chatMsg + "/n");
    chatContent.verticalScrollPosition =chatContent.textHeight;
    }
   
    incomingStream.client=i;
    remoteVideoDisplay.attachNetStream(incomingStream);
   }
   private function controlHandler(e:NetStatusEvent) {
    trace(e.info.code);
   }
   private function outgoingStreamHandler(e:NetStatusEvent) {
    outgoingStream.send("onIncomingCall",myNameTxt.text);
    trace(e.info.code);   
   }
   private function startAudio() {
    var myMic:Microphone=Microphone.getMicrophone(0);
    outgoingStream.attachAudio(myMic);
   }
   private function startVideo() {
    var myCam:Camera=Camera.getCamera();
    localVideoDisplay.attachCamera(myCam);
    outgoingStream.attachCamera(myCam);
   }   private function incomingStreamHandler(e:NetStatusEvent) {
    trace(e.info.code);
   }
   //向Web服务器提交完信息后为连接做准备
   private function completeRegistration() {
    listenerStream=new NetStream(myNC,NetStream.DIRECT_CONNECTIONS);
    listenerStream.addEventListener(NetStatusEvent.NET_STATUS,listenerHandler);
    listenerStream.publish("control" +myNameTxt.text);   
    var c:* = new Object();
    c.onPeerConnect = function (tmpNS:NetStream){
    var caller:* =tmpNS;
    incomingStream = new NetStream(myNC,caller.farID);
    incomingStream.addEventListener(NetStatusEvent.NET_STATUS, incomingStreamHandler);
    incomingStream.play("media-caller");
    var st:SoundTransform= new SoundTransform(50);
    incomingStream.soundTransform = st;
    incomingStream.receiveAudio(false);
    incomingStream.receiveVideo(false);
    var i:Object= new Object();
    i.onIncomingCall = function (tmpOppName:String){
    msgTxt.text=tmpOppName+"正在呼叫你,你接受吗?"
    acceptBtn.addEventListener(MouseEvent.CLICK,acceptCall)
    }
    i.onIm = function (userName:String,chatMsg:String){
    chatContent.text =chatContent.text + (userName+ ": " + chatMsg + "/n");
    chatContent.verticalScrollPosition =chatContent.textHeight;
    }
    incomingStream.client = i;
    };
    listenerStream.client=c;
   }
   private function listenerHandler(e:NetStatusEvent) {
    trace(e.info.code);
   }
  
   //接受呼叫
   public function acceptCall(e:MouseEvent) {
    msgTxt.text="你已经接受了对方的呼叫...";
    incomingStream.receiveAudio(true);
    incomingStream.receiveVideo(true);
    remoteVideoDisplay.attachNetStream(incomingStream);
    outgoingStream=new NetStream(myNC,NetStream.DIRECT_CONNECTIONS);
    outgoingStream.addEventListener(NetStatusEvent.NET_STATUS,outgoingStreamHandler);
    outgoingStream.publish("media-callee");
    var o:* = new Object();
    o.onPeerConnect = function (tmpNS:NetStream){
       trace(tmpNS.farID);    
    }
    ;
    outgoingStream.client=o;
    outgoingStream.send("onCallAccepted",myNameTxt.text);
    startVideo();
    startAudio();
   }
   //发送聊天信息
   private function sendChatMsg(e:MouseEvent) {
    var tmpMsg:* =chatTxt.text;   
    if (tmpMsg!=0&&outgoingStream) {
     chatContent.text=chatContent.text+myNameTxt.text+": "+tmpMsg+"/n";
     outgoingStream.send("onIm",myNameTxt.text,tmpMsg);
     chatTxt.text="";
    } else {
     chatContent.appendText("发送内容为空或连接尚未建立!"+"/n");
     chatTxt.text="";
    }
   }}
}