语音聊天室,或多人语音聊天,是即时通讯应用中常见的功能之一,好比,QQ的语音讨论组就是咱们用得比较多的。html
这篇文章将实现一个简单的语音聊天室,让多我的能够进入同一个房间进行语音沟通。先看运行效果截图:服务器
从左到右的三张图分别是:登陆界面、语音聊天室的主界面、标注了各个控件的主界面。网络
(若是以为界面太丑,不要紧,后面下载源码后,你能够本身美化~~)闭包
很明显,我这个语音聊天室采用的是C/S结构,整个项目结构相对比较简单,以下所示:框架
该项目的底层是基于OMCS构建的。这样,服务端就基本没写代码,直接把OMCS服务端拿过来用;客户端就比较麻烦些,下面我就重点讲客户端的开发。ui
客户端开发了多个自定义控件,而后将它们组装到一块儿,以完成语音聊天室的功能。为了便于讲解,我主界面的图作了标注,以指示出各个自定义控件。 this
如今咱们分别介绍各个控件:spa
分贝显示器用于显示声音的大小,好比麦克风采集到的声音的大小,或扬声器播放的声音的大小。如上图中3标注的。code
(1)傅立叶变换orm
将声音数据转换成分贝强度使用的是傅立叶变换。其对应的是客户端项目中的FourierTransformer静态类。源码比较简单,就不贴出来了,你们本身去看。
(2)声音强度显示控件 DecibelDisplayer
DecibelDisplayer 使用的是PrograssBar来显示声音强度的大小。
每当有声音数据交给DecibelDisplayer显示时,首先,DecibelDisplayer会调用上面的傅立叶变换将其转换为分贝,而后,将其映射为PrograssBar的对应的Value。
SpeakerPanel 用于表示聊天室中的一个成员,如上图中1所示。它显示了成员的ID,成员的声音的强度(使用DecibelDisplayer控件),以及其麦克风的状态(启用、引用)。
这个控件很重要,我将其源码贴出来:
public partial class SpeakerPanel : UserControl ,IDisposable { private ChatUnit chatUnit; public SpeakerPanel() { InitializeComponent(); this.SetStyle(ControlStyles.ResizeRedraw, true);//调整大小时重绘 this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);// 双缓冲 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);// 禁止擦除背景. this.SetStyle(ControlStyles.UserPaint, true);//自行绘制 this.UpdateStyles(); } public string MemberID { get { if (this.chatUnit == null) { return null; } return this.chatUnit.MemberID; } } public void Initialize(ChatUnit unit) { this.chatUnit = unit; this.skinLabel_name.Text = unit.MemberID; this.chatUnit.MicrophoneConnector.ConnectEnded += new CbGeneric<OMCS.Passive.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); } public void Initialize(string curUserID) { this.skinLabel_name.Text = curUserID; this.skinLabel_name.ForeColor = Color.Red; this.pictureBox_Mic.Visible = false; this.decibelDisplayer1.Visible = false; } 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 connectResult; void MicrophoneConnector_ConnectEnded(ConnectResult res) { if (this.InvokeRequired) { this.BeginInvoke(new CbGeneric<ConnectResult>(this.MicrophoneConnector_ConnectEnded), res); } else { this.connectResult = res; this.ShowMicState(); } } public void Dispose() { this.chatUnit.Close(); } private void ShowMicState() { if (this.connectResult != OMCS.Passive.ConnectResult.Succeed) { this.pictureBox_Mic.BackgroundImage = this.imageList1.Images[2]; this.toolTip1.SetToolTip(this.pictureBox_Mic, this.connectResult.ToString()); } else { this.decibelDisplayer1.Working = false; if (!this.chatUnit.MicrophoneConnector.OwnerOutput) { this.pictureBox_Mic.BackgroundImage = this.imageList1.Images[1]; this.toolTip1.SetToolTip(this.pictureBox_Mic, "好友禁用了麦克风"); return; } if (this.chatUnit.MicrophoneConnector.Mute) { this.pictureBox_Mic.BackgroundImage = this.imageList1.Images[1]; this.toolTip1.SetToolTip(this.pictureBox_Mic, "静音"); } else { this.pictureBox_Mic.BackgroundImage = this.imageList1.Images[0]; this.toolTip1.SetToolTip(this.pictureBox_Mic, "正常"); this.decibelDisplayer1.Working = true; } } } private void pictureBox_Mic_Click(object sender, EventArgs e) { if (!this.chatUnit.MicrophoneConnector.OwnerOutput) { return; } this.chatUnit.MicrophoneConnector.Mute = !this.chatUnit.MicrophoneConnector.Mute; this.ShowMicState(); } }
(1)在代码中,ChatUnit就表明当前这个聊天室中的成员。咱们使用其MicrophoneConnector链接到目标成员的麦克风。
(2)预约MicrophoneConnector的AudioDataReceived事件,当收到语音数据时,将其交给DecibelDisplayer去显示声音的大小。
(3)预约MicrophoneConnector的ConnectEnded和OwnerOutputChanged事件,根据其结果来显示SpeakerPanel空间上麦克风图标的状态(对应ShowMicState方法)。
MultiAudioChatContainer对应上图中2标注的控件,它主要作了如下几件事情:
(1)在初始化时,加入聊天室:经过调用IMultimediaManager的ChatGroupEntrance属性的Join方法。
(2)使用FlowLayoutPanel将聊天室中每一个成员对应的SpeakerPanel罗列出来。
(3)当有成员加入或退出聊天室时(对应ChatGroup的SomeoneJoin和SomeoneExit事件),动态添加或移除对应的SpeakerPanel实例。
(4)经过CheckBox将本身设备(麦克风和扬声器)的控制权暴露出来。咱们能够启用或禁用咱们本身的麦克风或扬声器。
(5)注意,其提供了Close方法,这意味着,在关闭包含了该控件的宿主窗体时,要调用其Close方法以释放其内部持有的麦克风链接器等资源。
在完成MultiAudioChatContainer后,咱们这个聊天室的核心就差很少了。接下来就是弄个主窗体,而后把MultiAudioChatContainer拖上去,初始化IMultimediaManager,并传递给MultiAudioChatContainer就大功告成了。
上面只是讲了实现多人语音聊天室中的几个重点,并不全面,你们下载下面的源码能够更深刻的研究。
最后,跟你们说说部署的步骤:
(1)将服务端部署在一台机器上,启动服务端。
(2)修改客户端配置文件中的ServerIP为刚才服务器的IP。
(3)在多台机器上运行客户端,以不一样的账号登陆到同一个房间(如默认的R1000)。
(4)如此,多个用户就处于同一个聊天室进行语音聊天了。
敬请了解:
ESFramework通讯框架 OMCS网络语音视频框架 MFile语音视频录制组件 MCapture语音视频采集组件 StriveEngine轻量级通讯引擎 OAUS 自动升级系统