語音聊天室,或多人語音聊天,是即時通訊應用中常見的功能之一,好比,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 自動升級系統