Dec 10

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

经过两天两夜的艰苦努力,史上第一个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="";
   }
  }

 }
}

相关文章

日志评论

  • quote 1.auzn comments at 2008/12/11 13:42:49 回复该留言

    牛人。
    收藏走人,哈哈

  • quote 2.pp comments at 2008/12/15 14:34:14 回复该留言

    不能使用了???

  • quote 3.西部秋虫 comments at 2008/12/15 15:03:25 回复该留言

    可以啊,不过要注意防火墙的问题,对于公司或企业的局域网而言,可能会限制UDP.

  • quote 4.pp comments at 2008/12/15 16:23:15 回复该留言

    我打开flash player就报错:
    ReferenceError: Error #1069: Property nearID not found on flash.net.NetConnection and there is no default value.
    at p2p/netStatus()

  • quote 5.西部秋虫 comments at 2008/12/15 16:42:19 回复该留言

    要用FlashPlayer10.

  • quote 6.pp comments at 2008/12/15 17:13:20 回复该留言

    用的就是fp10的debugger版,不过如果在浏览器中打开swf的话就可以。单独打开就会出错,估计是单独打开的swf无法启动udp连接。

  • quote 7.oyxiao comments at 2008/12/15 17:27:32 回复该留言

    fmsPath="rtmfp://stratus.adobe.com/HawkPrerelease-4e4efa13755c/FMSer.cn";
    WebServiceUrl="http://76.74.170.61/cgi-bin/reg";
    想知道后台用什么服务器
    和 WebServiceUrl 具体意思? 请教

  • quote 8.pp comments at 2008/12/15 18:06:55 回复该留言

    基本上rtmfp的作用就是生成一个网络上的唯一ID,相当于IP地址。WebServiceUrl地址的服务用来保存登陆的用户及其ID。当一个client想连接另外一个client的时候,从WebService中找到对应client的ID就可以确定对方了。

  • quote 9.西部秋虫 comments at 2008/12/15 18:52:55 回复该留言

    PP说的基本正确。其实我们不用WebService,只要能想办法(比如打电话,发QQ信息等:))知道对方的ID,就能建立P2P连接!

  • quote 10.chancidal comments at 2008/12/25 1:40:09 回复该留言

    有源文件吗?

  • quote 11.西部秋虫 comments at 2008/12/25 11:22:58 回复该留言

    有Code啊,UI自己根据Code做就行了.

  • quote 12.烟火 comments at 2009/2/11 17:33:09 回复该留言

    能否直接用UDP做? 监听端口,建立UDP连接. 这样的话就可以自己写服务器了.

  • quote 13.西部秋虫 comments at 2009/2/11 17:54:17 回复该留言

    应该可以,FlashPlayer10本身是支持P2P的.

  • quote 14.fishbone comments at 2009/4/11 12:50:13 回复该留言

    farID 和nearID是什么???

  • quote 15.西部秋虫 comments at 2009/4/11 22:52:41 回复该留言

    是stratus分配给客户端的ID。

  • quote 16.AZhang comments at 2009/4/12 22:47:29 回复该留言

    你好,请教你一个问题:
    现在我找到的例子中都是摄像头捕捉的视频点对点共享,如果我要做视频点播系统的话,是否需要通过FMS或RED5系统来发布作为种子的视频流?


  • quote 17.ouchen comments at 2011/10/7 13:11:21 回复该留言

    can you support me "FLA" source code files?

  • quote 18.西部秋虫 comments at 2011/10/8 14:36:25 回复该留言

    It is too old to find it,you can download the swf file and decompiler it to get fla.

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。