Fms3和Flex打造在线多人视频会议和视频聊天(附原代码)

  1. 云栖社区>
  2. 博客>
  3. 正文

Fms3和Flex打造在线多人视频会议和视频聊天(附原代码)

范大脚脚 2017-12-07 11:45:00 浏览903
展开阅读全文
Flex,Fms3系列文章导航
Flex,Fms3相关文章索引
 

本篇是视频聊天,会议开发实例系列文章的第3篇,该系列所有文章链接如下: 
http://www.cnblogs.com/aierong/archive/2008/12/30/Flex.html#sp

 

1.工作原理
NetStream.publish方法的应用
publish () 方法:将音频流、视频流和文本消息流从客户端发送到 Flash Media Server,并可选择在传输期间录制该流。 此方法仅供指定的流的发布者使用。
第1个参数:标识该流的字符串。
第2个参数:指定如何发布该流的字符串。 有效值为“record”、“append”和“live”。 默认值为“live”。 (这3个参数区别如下:)
如果传递“record”,Flash Player 将发布并录制实时数据,同时将录制的数据保存到名称与传递给 name 参数的值相匹配的新文件中。 该文件保存在服务器上服务器应用程序所在目录的子目录中。 如果该文件存在,则覆盖该文件。
如果传递“append”,Flash Player 将发布并录制实时数据,同时将录制的数据附加到名称与传递给 name 参数的值相匹配的文件中,该文件存储在服务器上包含服务器应用程序的目录的子目录中。如果未找到与 name 参数相匹配的文件,则创建一个文件。 
如果省略此参数或传递“live”,则 Flash Player 将发布实时数据而不进行录制。 如果存在名称与传递给 name 参数的值相匹配的文件,则删除它。

关于NetStream.publish方法还可以看我上篇文章
http://www.cnblogs.com/aierong/archive/2009/01/10/flex_fms_video_start.html

要实现视频会议就是使用的“live”这一类型

来看一下原理图,参加会议的用户将自己本地摄像头捕捉到的画面publish到fms,存放在fms端userList这个集合对象中,集合中存放的是每个用户名也就是他们发布视频的名字。每当用新用户加入或者退出会议的时候,fms就把这个userList广播给每个还在线的用户。用户取得userList只需播放其他几个用户的视频即可。怎么样原理很简单吧! 


 

2.准备工作
在fms安装目录下的application中,新建一个文件夹test_video2,然后启动fms服务器

 

3.开始代码
这次代码分2部分:服务器端的asc文件和客户端

asc文件中有2个重要的类:
Application类:Application类包含有关一个Flash Media Server应用程序实例的信息,它会一直维持这些信息直到这个应用程序实例被卸载。
Client类:Client类让你处理连接到一个Flash Media Server应用程序实例的每一个用户或说client。

Application类有几个重要事件如下:
Application.onAppStart 当这个应用程序被服务器装载时调用。
Application.onAppStop 当这个应用程序被服务器卸载时调用。
Application.onConnect 当一个客户机连接到这个应用程序时调用。
Application.onDisconnect 当一个客户机从这个应用程序断开连接时调用。

Application类有几个重要方法如下:
Application.acceptConnection() 接受一个来自客户机的至一个应用程序的连接。
Application.broadcastMsg() 向所有连接的客户机广播一条消息。
Application.disconnect() 从服务器断开一个客户机的连接。
Application.rejectConnection() 拒绝至一个应用程序的连接。

Client类有1重要方法如下:
Client.call() 在Flash客户机上异步的执行一个方法,并把值从Flash客户机返回到服务器。

 

4.先编写asc文件,打开写字板,键入下面代码,并保存为test_video2.asc,然后copy此文件到test_video2文件夹(asc文件要求和文件夹同名或者叫main.asc)
userList=[];

application.onAppStart=function()
{
 trace("fms服务器启动......");
}

application.onConnect = function(currentClient)
{
 application.acceptConnection(currentClient);
 if (userList.length>=3)
 {
  currentClient.call("showServerMsg",null,"已经达到最大用户数");
  application.rejectConnection(currentClient);
 }
 else
 {                 
  currentClient.communicateServer= function(value)
  {
   currentClient.username=value;
   trace(currentClient.username+"加入聊天室");
   userList.push(value);
   trace("当前用户列表"+userList);
   application.broadcastMsg("playOtherVideo",userList);
  }
 }
}

application.onDisconnect=function(currentClient)
{
 trace("用户"+currentClient.username+"离开聊天室");
 
 for(j=0;j<userList.length;j++)
 {
  if ( userList[j]==currentClient.username )
  {
   userList.splice(j,1);
  }
 }
 trace("当前用户列表"+userList);
 application.broadcastMsg("playOtherVideo",userList);
}

代码说明:
(1)application.broadcastMsg ("客户端方法名",参数..);是asc中一个比较重要的方法,他的作用是向所有连接着的客户端进行广播,调用客户端的函数。这个方法相当于循环遍历Application.clients数组并在每一个独立的客户机上调用Client.call(),但这个方法的效率更高(尤其是当连接的客户机数量很大时)。唯一的不同是当你调用broadcastMsg()时你不能指定一个响应对象,除此以外,两种语法是一样的。
(2)userList.splice(a,b)这个函数,它的作用是从a位置开始移除数组中的b个元素(asc用的是as1语法)
(3)代码中做了限制,只允许最多3人连接fms


5.打开Fb3,创建一个项目

 

6.在主mxml中拖动控件,界面如下:

具体代码如下:
<mx:Label x="10" y="10" text="你的画面"/>
<mx:VideoDisplay x="10" y="38" width="120" height="90" id="vd_myVideo"/>
<mx:TextInput x="152" y="38" text="输入你的名字" id="txt_username" width="116" focusIn="txt_username.text=''"/>
<mx:Button x="288" y="38" label="进入聊天室" id="btn_start"/>
<mx:VBox x="10" y="161" width="120" id="vb_otherVideo">
</mx:VBox>

 

7.导入包和定义变量如下:
import mx.controls.Label;
 
import mx.controls.Alert;
 
private var netConnection:NetConnection;
private var outNetStream:NetStream;
private var camera:Camera;
private var microphone:Microphone;
private var responder:Responder;
private var appServer:String="rtmp://192.168.0.249/test_video2";
private var username:String="";

代码说明:
outNetStream就是你要发布给fms的视频流,通俗的说就是你的画面 
responder 如果client端调用server端as1代码中的某个方法需要有回调函数的话就要定义这个responder,后面会有具体说明 
username 每个用户的用户名,也就是发布时候给视频取得名字

 

8.creationComplete="init()",页面初始化代码
private function init():void
{
 netConnection = new NetConnection();
 netConnection.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
 netConnection.connect(appServer);
 netConnection.client=this;
 initMedia();
}
  
private function initMedia():void
{
 camera = Camera.getCamera();
 camera.setMode(120,90,15);
 camera.setQuality(0,90);
 vd_myVideo.attachCamera(camera);
 microphone=Microphone.getMicrophone();
}

private function netStatusHandler(evt:NetStatusEvent):void
{
 trace(evt.info.code);
   
 if ( evt.info.code=="NetConnection.Connect.Success" )
 {
  btn_start.addEventListener(MouseEvent.CLICK,startCommunicate);
 }
 else
 {
  Alert.show("fms连接失败"+evt.info.code);
 }
}
代码比较简单,不明白可以看我上篇
http://www.cnblogs.com/aierong/archive/2009/01/10/flex_fms_video_start.html

 

9.实现按钮事件
private function startCommunicate(evt:MouseEvent):void
{
 username=txt_username.text;
 responder=new Responder(communicateStataHandler);
 netConnection.call("communicateServer",responder,username);
}

private function communicateStataHandler(str:String):void
{
 outMyVideo();
 btn_start.enabled=false;
}

private function outMyVideo():void
{
 /* 发布视频 */
 outNetStream = new NetStream(netConnection);
 outNetStream.attachCamera(camera);
 outNetStream.attachAudio(microphone);
 outNetStream.publish(username,"live");
}
代码说明:
Responder 类提供了一个对象,该对象在 NetConnection.call() 中使用以处理来自与特定操作成功或失败相关的服务器的返回值。 
netConnection.call调用asc文件中的communicateServer,调用成功后,回调communicateStataHandler方法

 

10.showServerMsg方法实现
public function showServerMsg(msg:String):void
{
 Alert.show(msg);
}
代码说明:
供asc文件中调用

 

11.playOtherVideo方法实现:
public function playOtherVideo(newUserList:Array):void
{
 vb_otherVideo.removeAllChildren();
  
 for(var i:int=0;i<newUserList.length;i++)
 {
  if ( newUserList[i]!=username )
  {
   var vd:VideoDisplay = new VideoDisplay();
   var video:Video = new Video();
   video.width=120;
   video.height=90;
   var inNetStream:NetStream= new NetStream(netConnection);
   video.attachNetStream(inNetStream);
   inNetStream.play(newUserList[i]);
   var label:Label= new Label();
   label.text=newUserList[i]+"的画面";
     
   vd.addChild(video);
   vd.width=120;
   vd.height=90;
   vb_otherVideo.addChild(label);
   vb_otherVideo.addChild(vd);       
  }
 }
}
代码说明:
asc文件中application.broadcastMsg方法调用,向所有连接的客户机广播

 

12.运行程序,图片如下,其中有一人没视频摄像头


 

13.代码下载
http://files.cnblogs.com/aierong/Video2.rar
您收到代码后,请回到文章下面留言告之一下!要是没收到,我可以再发!

提供代码是为了互相学习,一起探讨!请大家多交流!
1.要是对代码有什么疑问,可以在文章的评论区留言,我会尽我所能答复您!
2.要是您在运行代码的过程中发现bug,或者是您有什么好的建议和意见,也可以在文章的评论区留言给我,我会及时更正!

 


评论区使用提示:
评论区留言(使用高级评论)是可以贴图片的,要是有难以描述的问题,可以贴图片和文字一起说明
谢谢!

 

 


收藏与分享
收藏到QQ书签 添加到百度搜藏 添加到百度搜藏 添加到雅虎收藏 分享到饭否 收藏到就喜欢网络收藏夹 

RSS订阅我 什么是RSS?
feedsky    http://wap.feedsky.com/aierongrss    E-mail 
订阅到雅蛙        使用RSS邮天下订阅    订阅到有道阅读 
订阅到抓虾    鲜果阅读器订阅图标    Add to Google 
訂閱 Bloglines    哪吒提醒    Subscribe in NewsGator Online

东莞.net俱乐部
东莞.net俱乐部 欢迎您的加入

 

 

我的系列文章
A.Sql Server2005 Transact-SQL 新兵器学习 
B.MCAD学习 
C.代码阅读总结 
D.ASP.NET状态管理 
E.DB(数据库) 
F.WAP 
G.WinForm 
H.Flex

我的好文推荐
FlexAir开源版-全球免费多人视频聊天室,免费网络远程多人视频会议系统((Flex,Fms3联合开发))<视频聊天,会议开发实例8> 
Sql Server2005 Transact-SQL 新兵器学习总结之-总结 
MS SQL数据库备份和恢复存储过程(加强版本) 
sql server中分布式查询随笔(链接服务器(sp_addlinkedserver)和远程登录映射(sp_addlinkedsrvlogin)使用小总结) 
ASP.NET2.0国际化/本地化应用程序的实现总结(多语言,多文化页面的实现) 
WAP开发资料站(最新更新) 
自定义格式字符串随笔 (IFormattable,IFormatProvider,ICustomFormatter三接口的实现) 
Mcad学习笔记之异步编程(AsyncCallback 委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法的使用小总结) 
Mcad学习笔记之通过反射调用類的方法,屬性,字段,索引器(2種方法) 
Mcad学习笔记之序列化(2进制和Soap序列 化) 
Mcad学习笔记之委托再理解(delegate的构造器,BeginInvoke,EndInvoke,Invoke4个方法的探讨) 
ASP.NET状态管理之一(概括篇) 
Flex,Fms学习笔记

banner

希望上面提到的知识对您有所提示,同时欢迎交流和指正 
作者:aierong
出处:http://www.cnblogs.com/aierong
贴子以"现状"提供且没有任何担保,同时也没有授予任何权利!
本文版权归作者所有,欢迎转载!


原创技术文章和心得,转载注明出处!这也是对原创者的尊重!




Flex,Fms3系列文章导航
  1. Flex,Fms3相关文章索引

 

本篇是视频聊天,会议开发实例系列文章的第3篇,该系列所有文章链接如下: 
http://www.cnblogs.com/aierong/archive/2008/12/30/Flex.html#sp

 

1.工作原理
NetStream.publish方法的应用
publish () 方法:将音频流、视频流和文本消息流从客户端发送到 Flash Media Server,并可选择在传输期间录制该流。 此方法仅供指定的流的发布者使用。
第1个参数:标识该流的字符串。
第2个参数:指定如何发布该流的字符串。 有效值为“record”、“append”和“live”。 默认值为“live”。 (这3个参数区别如下:)
如果传递“record”,Flash Player 将发布并录制实时数据,同时将录制的数据保存到名称与传递给 name 参数的值相匹配的新文件中。 该文件保存在服务器上服务器应用程序所在目录的子目录中。 如果该文件存在,则覆盖该文件。
如果传递“append”,Flash Player 将发布并录制实时数据,同时将录制的数据附加到名称与传递给 name 参数的值相匹配的文件中,该文件存储在服务器上包含服务器应用程序的目录的子目录中。如果未找到与 name 参数相匹配的文件,则创建一个文件。 
如果省略此参数或传递“live”,则 Flash Player 将发布实时数据而不进行录制。 如果存在名称与传递给 name 参数的值相匹配的文件,则删除它。

关于NetStream.publish方法还可以看我上篇文章
http://www.cnblogs.com/aierong/archive/2009/01/10/flex_fms_video_start.html

要实现视频会议就是使用的“live”这一类型

来看一下原理图,参加会议的用户将自己本地摄像头捕捉到的画面publish到fms,存放在fms端userList这个集合对象中,集合中存放的是每个用户名也就是他们发布视频的名字。每当用新用户加入或者退出会议的时候,fms就把这个userList广播给每个还在线的用户。用户取得userList只需播放其他几个用户的视频即可。怎么样原理很简单吧! 
2009011414563168.jpg

 

2.准备工作
在fms安装目录下的application中,新建一个文件夹test_video2,然后启动fms服务器

 

3.开始代码
这次代码分2部分:服务器端的asc文件和客户端

asc文件中有2个重要的类:
Application类:Application类包含有关一个Flash Media Server应用程序实例的信息,它会一直维持这些信息直到这个应用程序实例被卸载。
Client类:Client类让你处理连接到一个Flash Media Server应用程序实例的每一个用户或说client。

Application类有几个重要事件如下:
Application.onAppStart 当这个应用程序被服务器装载时调用。
Application.onAppStop 当这个应用程序被服务器卸载时调用。
Application.onConnect 当一个客户机连接到这个应用程序时调用。
Application.onDisconnect 当一个客户机从这个应用程序断开连接时调用。

Application类有几个重要方法如下:
Application.acceptConnection() 接受一个来自客户机的至一个应用程序的连接。
Application.broadcastMsg() 向所有连接的客户机广播一条消息。
Application.disconnect() 从服务器断开一个客户机的连接。
Application.rejectConnection() 拒绝至一个应用程序的连接。

Client类有1重要方法如下:
Client.call() 在Flash客户机上异步的执行一个方法,并把值从Flash客户机返回到服务器。

 

4.先编写asc文件,打开写字板,键入下面代码,并保存为test_video2.asc,然后copy此文件到test_video2文件夹(asc文件要求和文件夹同名或者叫main.asc)
userList=[];

application.onAppStart=function()
{
 trace("fms服务器启动......");
}

application.onConnect = function(currentClient)
{
 application.acceptConnection(currentClient);
 if (userList.length>=3)
 {
  currentClient.call("showServerMsg",null,"已经达到最大用户数");
  application.rejectConnection(currentClient);
 }
 else
 {                 
  currentClient.communicateServer= function(value)
  {
   currentClient.username=value;
   trace(currentClient.username+"加入聊天室");
   userList.push(value);
   trace("当前用户列表"+userList);
   application.broadcastMsg("playOtherVideo",userList);
  }
 }
}

application.onDisconnect=function(currentClient)
{
 trace("用户"+currentClient.username+"离开聊天室");
 
 for(j=0;j<userList.length;j++)
 {
  if ( userList[j]==currentClient.username )
  {
   userList.splice(j,1);
  }
 }
 trace("当前用户列表"+userList);
 application.broadcastMsg("playOtherVideo",userList);
}

代码说明:
(1)application.broadcastMsg ("客户端方法名",参数..);是asc中一个比较重要的方法,他的作用是向所有连接着的客户端进行广播,调用客户端的函数。这个方法相当于循环遍历Application.clients数组并在每一个独立的客户机上调用Client.call(),但这个方法的效率更高(尤其是当连接的客户机数量很大时)。唯一的不同是当你调用broadcastMsg()时你不能指定一个响应对象,除此以外,两种语法是一样的。
(2)userList.splice(a,b)这个函数,它的作用是从a位置开始移除数组中的b个元素(asc用的是as1语法)
(3)代码中做了限制,只允许最多3人连接fms


5.打开Fb3,创建一个项目

 

6.在主mxml中拖动控件,界面如下:
2009011414570718.jpg
具体代码如下:
<mx:Label x="10" y="10" text="你的画面"/>
<mx:VideoDisplay x="10" y="38" width="120" height="90" id="vd_myVideo"/>
<mx:TextInput x="152" y="38" text="输入你的名字" id="txt_username" width="116" focusIn="txt_username.text=''"/>
<mx:Button x="288" y="38" label="进入聊天室" id="btn_start"/>
<mx:VBox x="10" y="161" width="120" id="vb_otherVideo">
</mx:VBox>

 

7.导入包和定义变量如下:
import mx.controls.Label;
 
import mx.controls.Alert;
 
private var netConnection:NetConnection;
private var outNetStream:NetStream;
private var camera:Camera;
private var microphone:Microphone;
private var responder:Responder;
private var appServer:String="rtmp://192.168.0.249/test_video2";
private var username:String="";

代码说明:
outNetStream就是你要发布给fms的视频流,通俗的说就是你的画面 
responder 如果client端调用server端as1代码中的某个方法需要有回调函数的话就要定义这个responder,后面会有具体说明 
username 每个用户的用户名,也就是发布时候给视频取得名字

 

8.creationComplete="init()",页面初始化代码
private function init():void
{
 netConnection = new NetConnection();
 netConnection.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler);
 netConnection.connect(appServer);
 netConnection.client=this;
 initMedia();
}
  
private function initMedia():void
{
 camera = Camera.getCamera();
 camera.setMode(120,90,15);
 camera.setQuality(0,90);
 vd_myVideo.attachCamera(camera);
 microphone=Microphone.getMicrophone();
}

private function netStatusHandler(evt:NetStatusEvent):void
{
 trace(evt.info.code);
   
 if ( evt.info.code=="NetConnection.Connect.Success" )
 {
  btn_start.addEventListener(MouseEvent.CLICK,startCommunicate);
 }
 else
 {
  Alert.show("fms连接失败"+evt.info.code);
 }
}
代码比较简单,不明白可以看我上篇
http://www.cnblogs.com/aierong/archive/2009/01/10/flex_fms_video_start.html

 

9.实现按钮事件
private function startCommunicate(evt:MouseEvent):void
{
 username=txt_username.text;
 responder=new Responder(communicateStataHandler);
 netConnection.call("communicateServer",responder,username);
}

private function communicateStataHandler(str:String):void
{
 outMyVideo();
 btn_start.enabled=false;
}

private function outMyVideo():void
{
 /* 发布视频 */
 outNetStream = new NetStream(netConnection);
 outNetStream.attachCamera(camera);
 outNetStream.attachAudio(microphone);
 outNetStream.publish(username,"live");
}
代码说明:
Responder 类提供了一个对象,该对象在 NetConnection.call() 中使用以处理来自与特定操作成功或失败相关的服务器的返回值。 
netConnection.call调用asc文件中的communicateServer,调用成功后,回调communicateStataHandler方法

 

10.showServerMsg方法实现
public function showServerMsg(msg:String):void
{
 Alert.show(msg);
}
代码说明:
供asc文件中调用

 

11.playOtherVideo方法实现:
public function playOtherVideo(newUserList:Array):void
{
 vb_otherVideo.removeAllChildren();
  
 for(var i:int=0;i<newUserList.length;i++)
 {
  if ( newUserList[i]!=username )
  {
   var vd:VideoDisplay = new VideoDisplay();
   var video:Video = new Video();
   video.width=120;
   video.height=90;
   var inNetStream:NetStream= new NetStream(netConnection);
   video.attachNetStream(inNetStream);
   inNetStream.play(newUserList[i]);
   var label:Label= new Label();
   label.text=newUserList[i]+"的画面";
     
   vd.addChild(video);
   vd.width=120;
   vd.height=90;
   vb_otherVideo.addChild(label);
   vb_otherVideo.addChild(vd);       
  }
 }
}
代码说明:
asc文件中application.broadcastMsg方法调用,向所有连接的客户机广播

 

12.运行程序,图片如下,其中有一人没视频摄像头
2009011414580877.jpg

 

13.代码下载
http://files.cnblogs.com/aierong/Video2.rar
您收到代码后,请回到文章下面留言告之一下!要是没收到,我可以再发!

提供代码是为了互相学习,一起探讨!请大家多交流!
1.要是对代码有什么疑问,可以在文章的评论区留言,我会尽我所能答复您!
2.要是您在运行代码的过程中发现bug,或者是您有什么好的建议和意见,也可以在文章的评论区留言给我,我会及时更正!

 


评论区使用提示:
评论区留言(使用高级评论)是可以贴图片的,要是有难以描述的问题,可以贴图片和文字一起说明
谢谢!

 

 


收藏与分享

收藏到QQ书签 添加到百度搜藏 添加到百度搜藏 add2myweb.gif添加到雅虎收藏 分享到饭否 收藏到就喜欢网络收藏夹 vivi_coop.gif

RSS订阅我 什么是RSS?

feedsky    http://wap.feedsky.com/aierongrss    E-mail 
订阅到雅蛙    ico_sub4.gif    使用RSS邮天下订阅    订阅到有道阅读 
订阅到抓虾    鲜果阅读器订阅图标    Add to Google 
訂閱 Bloglines    哪吒提醒    Subscribe in NewsGator Online

东莞.net俱乐部

东莞.net俱乐部 欢迎您的加入

 

 

我的系列文章
A.Sql Server2005 Transact-SQL 新兵器学习 
B.MCAD学习 
C.代码阅读总结 
D.ASP.NET状态管理 
E.DB(数据库) 
F.WAP 
G.WinForm 
H.Flex

我的好文推荐
FlexAir开源版-全球免费多人视频聊天室,免费网络远程多人视频会议系统((Flex,Fms3联合开发))<视频聊天,会议开发实例8> 
Sql Server2005 Transact-SQL 新兵器学习总结之-总结 
MS SQL数据库备份和恢复存储过程(加强版本) 
sql server中分布式查询随笔(链接服务器(sp_addlinkedserver)和远程登录映射(sp_addlinkedsrvlogin)使用小总结) 
ASP.NET2.0国际化/本地化应用程序的实现总结(多语言,多文化页面的实现) 
WAP开发资料站(最新更新) 
自定义格式字符串随笔 (IFormattable,IFormatProvider,ICustomFormatter三接口的实现) 
Mcad学习笔记之异步编程(AsyncCallback 委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法的使用小总结) 
Mcad学习笔记之通过反射调用類的方法,屬性,字段,索引器(2種方法) 
Mcad学习笔记之序列化(2进制和Soap序列 化) 
Mcad学习笔记之委托再理解(delegate的构造器,BeginInvoke,EndInvoke,Invoke4个方法的探讨) 
ASP.NET状态管理之一(概括篇) 
Flex,Fms学习笔记

banner




本文转自aierong博客园博客,原文链接:http://www.cnblogs.com/aierong/archive/2009/01/14/Flex_Fms_VideoChat.html如需转载请自行联系原作者

网友评论

登录后评论
0/500
评论
范大脚脚
+ 关注