
文章“ C#实现语音聊天”发表后,许多朋友建议我也建立一个视频作为参考. 实际上,视频和语音的原理是相似的,因为添加了. 视频处理的逻辑将更加复杂. 本文实现了一个简单的视频聊天系统,该系统允许多个人进入同一房间进行语音和视频通信. 首先看一下由3个人执行的视频聊天的运行效果的屏幕截图:


以上两个屏幕截图分别是: 登录界面,标有各种控件的视频主界面.
很明显,我的语音使用C / S结构,整个项目结构相对简单,如下所示:

像语音一样,该项目的底层也基于OMCS语音和视频框架. 这样,服务器不编写任何代码,而直接使用OMCS服务器. 客户比较麻烦. 下面,我将重点介绍客户端的开发.
客户端开发了多个自定义控件,然后将它们组装在一起以完成视频的功能. 为了便于说明,我的主界面上的图片被标记为指示每个自定义控件.

现在,我们分别介绍每个控件:
分贝显示器用于显示声音的大小,例如麦克风收集的声音或扬声器播放的声音. 如上面的图2所示.
(1)傅立叶变换
傅里叶变换用于将声音数据转换为强度. 它对应于客户端项目中的FourierTransformer静态类. 源代码相对简单,因此将不会发布. 让我们自己看看吧.
(2)声音强度显示控件DecibelDisplayer
DecibelDisplayer使用PrograssBar显示声音强度.
只要有声音数据移交给DecibelDisplayer进行显示,首先,DecibelDisplayer就会调用上面的傅里叶变换将其转换为分贝,然后将其映射到相应的PrograssBar值.
VideoPanel用于表示中的成员,如上面的1所示. 它显示成员的ID,成员的声音强度(使用DecibelDisplayer控件),麦克风的状态(启用,禁用),的状态(不可用讨论组语音怎么开,正常,禁用),成员的视频,等

此控件非常重要,我发布了其源代码:

public partial class VideoPanel : UserControl { private IChatUnit chatUnit; private bool isMySelf = false; public VideoPanel() { InitializeComponent(); } /// <summary> /// 初始化成员视频显示控件。 /// </summary> public void Initialize(IChatUnit unit ,bool myself) { this.chatUnit = unit; this.isMySelf = myself; this.toolStripLabel_displayName.Text = unit.MemberID; this.decibelDisplayer1.Visible = !myself; //初始化麦克风连接器 this.chatUnit.MicrophoneConnector.Mute = myself; this.chatUnit.MicrophoneConnector.SpringReceivedEventWhenMute = myself; this.chatUnit.MicrophoneConnector.ConnectEnded += new CbGeneric<ConnectResult>(MicrophoneConnector_ConnectEnded); this.chatUnit.MicrophoneConnector.OwnerOutputChanged += new CbGeneric(MicrophoneConnector_OwnerOutputChanged); this.chatUnit.MicrophoneConnector.AudioDataReceived += new CbGeneric<byte[]>(MicrophoneConnector_AudioDataReceived); this.chatUnit.MicrophoneConnector.BeginConnect(unit.MemberID); //初始化连接器 this.chatUnit.DynamicCameraConnector.SetViewer(this.skinPanel1); this.chatUnit.DynamicCameraConnector.ConnectEnded += new CbGeneric<ConnectResult>(DynamicCameraConnector_ConnectEnded); this.chatUnit.DynamicCameraConnector.OwnerOutputChanged += new CbGeneric(DynamicCameraConnector_OwnerOutputChanged); this.chatUnit.DynamicCameraConnector.BeginConnect(unit.MemberID); } //好友启用或禁用 void DynamicCameraConnector_OwnerOutputChanged() { if (this.InvokeRequired) { this.BeginInvoke(new CbGeneric(this.DynamicCameraConnector_OwnerOutputChanged)); } else { this.ShowCameraState(); } } private ConnectResult connectCameraResult; //连接器尝试连接的结果 void DynamicCameraConnector_ConnectEnded(ConnectResult res) { if (this.InvokeRequired) { this.BeginInvoke(new CbGeneric<ConnectResult>(this.DynamicCameraConnector_ConnectEnded), res); } else { this.label_tip.Visible = false; this.connectCameraResult = res; this.ShowCameraState(); } } /// <summary> /// 综合显示的状态。 /// </summary> private void ShowCameraState() { if (this.connectCameraResult != OMCS.Passive.ConnectResult.Succeed) { this.pictureBox_Camera.BackgroundImage = null; this.pictureBox_Camera.BackgroundImage = this.imageList2.Images[2]; this.pictureBox_Camera.Visible = true; this.toolTip1.SetToolTip(this.pictureBox_Camera, this.connectCameraResult.ToString()); } else { this.pictureBox_Camera.Visible = !this.chatUnit.DynamicCameraConnector.OwnerOutput; if (!this.chatUnit.DynamicCameraConnector.OwnerOutput) { this.pictureBox_Camera.BackgroundImage = this.imageList2.Images[1]; this.toolTip1.SetToolTip(this.pictureBox_Camera, "被主人禁用!"); return; } } } //将接收到的声音数据交给分贝显示器显示 void MicrophoneConnector_AudioDataReceived(byte[] data) { this.decibelDisplayer1.DisplayAudioData(data); } //好友启用或禁用麦克风 void MicrophoneConnector_OwnerOutputChanged() { if (this.InvokeRequired) { this.BeginInvoke(new CbGeneric(this.MicrophoneConnector_OwnerOutputChanged)); } else { this.ShowMicState(); } } private ConnectResult connectMicResult; //麦克风连接器尝试连接的结果 void MicrophoneConnector_ConnectEnded(ConnectResult res) { if (this.InvokeRequired) { this.BeginInvoke(new CbGeneric<ConnectResult>(this.MicrophoneConnector_ConnectEnded), res); } else { this.connectMicResult = res; this.ShowMicState(); } } /// <summary> /// 综合显示麦克风的状态。 /// </summary> private void ShowMicState() { if (this.connectMicResult != OMCS.Passive.ConnectResult.Succeed) { this.pictureBox_Mic.Visible = true; this.toolTip1.SetToolTip(this.pictureBox_Mic, this.connectMicResult.ToString()); } else { this.decibelDisplayer1.Working = false; this.pictureBox_Mic.Visible = !this.chatUnit.MicrophoneConnector.OwnerOutput; this.decibelDisplayer1.Visible = this.chatUnit.MicrophoneConnector.OwnerOutput && !this.isMySelf; if (!this.chatUnit.MicrophoneConnector.OwnerOutput) { this.pictureBox_Mic.BackgroundImage = this.imageList1.Images[1]; this.toolTip1.SetToolTip(this.pictureBox_Mic, "麦克风被主人禁用!"); return; } this.pictureBox_Mic.Visible = !isMySelf; if (this.chatUnit.MicrophoneConnector.Mute) { this.pictureBox_Mic.BackgroundImage = this.imageList1.Images[1]; this.toolTip1.SetToolTip(this.pictureBox_Mic, "静音"); } else { this.pictureBox_Mic.Visible = false; this.pictureBox_Mic.BackgroundImage = this.imageList1.Images[0]; this.toolTip1.SetToolTip(this.pictureBox_Mic, "正常"); this.decibelDisplayer1.Working = true; } } } /// <summary> /// 展开或收起视频面板。 /// </summary> private void toolStripButton1_Click(object sender, EventArgs e) { try { if (this.Height > this.toolStrip1.Height) { this.toolStripButton1.Text = "展开"; this.toolStripButton1.Image = Resources.Hor; this.chatUnit.DynamicCameraConnector.SetViewer(null); this.Height = this.toolStrip1.Height; } else { this.toolStripButton1.Text = "收起"; this.toolStripButton1.Image = Resources.Ver; this.chatUnit.DynamicCameraConnector.SetViewer(this.skinPanel1); } } catch (Exception ee) { MessageBox.Show(ee.Message); } } }

(1)在代码中,IChatUnit表示此中的当前成员. 我们使用其MicrophoneConnector连接到目标成员的麦克风,并使用DynamicCameraConnector连接到目标成员的摄像机.
(2)安排MicrophoneConnector的AudioDataReceived事件,并在其接收语音数据时,将其提供给DecibelDisplayer以显示声音的大小.
(3)调度MicrophoneConnector的ConnectEnded和OwnerOutputChanged事件,并根据结果(对应于ShowMicState方法)在VideoPanel控件上显示麦克风图标的状态.
(4)安排DynamicCameraConnector的ConnectEnded和OwnerOutputChanged事件,并根据结果(与ShowCameraState方法相对应)在VideoPanel控件上显示摄像机图标的状态.

MultiAudioChatContainer对应于上图中标记为3的控件,它主要做以下事情:
(1)在初始化期间加入: 通过调用IMultimediaManager的ChatGroupEntrance属性的Join方法.
(2)使用FlowLayoutPanel列出与中每个成员相对应的VideoPanel.
(3)当成员加入或离开时(对应于ChatGroup的SomeGroupJoin和SomeoneExit事件),将动态添加或删除相应的VideoPanel实例.
(4)通过CheckBox公开对自己的设备(相机,麦克风,扬声器)的控制. 我们可以启用或禁用我们自己的麦克风或扬声器.
(5)请注意,它提供了Close方法,这意味着当您关闭包含该控件的宿主窗体时,需要调用其Close方法以释放其中包含的麦克风连接器,相机连接器等.
完成MultiAudioChatContainer后,我们的核心几乎相同. 下一步是获取主窗体,然后向上拖动MultiVideoChatContainer,初始化IMultimediaManager,然后将其传递给MultiVideoChatContainer讨论组语音怎么开,您就完成了.
以上内容仅讨论了实现视频的几个关键点. 它不全面. 您可以下载以下源代码以进行更深入的研究.

VideoChatRoom.rar
最后,向所有人介绍部署步骤:
(1)在服务器上部署服务器并启动服务器.
(2)将客户端配置文件中的ServerIP修改为刚才的服务器IP.
(3)在多台计算机上运行客户端,并使用不同的帐户(例如默认的R1000)登录到同一房间.
(4)这样,多个用户可以在同一个中进行视频聊天.
zhuweisky

原始文章390赞扬398次访问106万+
关注他的留言板
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/ruanjian/article-212011-1.html
最好直白警告