基於UDP協議實現P2P語音聊天系統(C#版本)
原創性申明
概述
基於事件模型的UDP通訊框架(適用於網路包編解碼)】已經實現過了UDP的分包傳送資料的功能,而這篇文章主要是一個應用,使用UDP協議傳送語音和文字等資訊。在這個系統中沒有服務端和客戶端,相互通訊都是直接相互聯絡的,能夠很好的實現效果。
具體實現
1、語言資料來源獲取
要想傳送語音資訊,首先得獲取語音,這裡有幾種方法,一種是使用DirectX的DirectXsound來錄音,我為了簡便使用一個開源的外掛NAudio來實現語音錄取。 首先在專案中引用NAudio.dll元件,具體的實現程式碼如下所示:
上面的程式碼實現了錄音,並且寫入本地檔案p2psound_A.wav中儲存//------------------錄音相關----------------------------- private IWaveIn waveIn; private WaveFileWriter writer; private void LoadWasapiDevicesCombo() { var deviceEnum = new MMDeviceEnumerator(); var devices = deviceEnum.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active).ToList(); comboBox1.DataSource = devices; comboBox1.DisplayMember = "FriendlyName"; } private void CreateWaveInDevice() { waveIn = new WaveIn(); waveIn.WaveFormat = new WaveFormat(8000, 1); waveIn.DataAvailable += OnDataAvailable; waveIn.RecordingStopped += OnRecordingStopped; } void OnDataAvailable(object sender, WaveInEventArgs e) { if (this.InvokeRequired) { this.BeginInvoke(new EventHandler<WaveInEventArgs>(OnDataAvailable), sender, e); } else { writer.Write(e.Buffer, 0, e.BytesRecorded); int secondsRecorded = (int)(writer.Length / writer.WaveFormat.AverageBytesPerSecond); if (secondsRecorded >= 10)//最大10s { StopRecord(); } else { l_sound.Text = secondsRecorded + " s"; } } } void OnRecordingStopped(object sender, StoppedEventArgs e) { if (InvokeRequired) { BeginInvoke(new EventHandler<StoppedEventArgs>(OnRecordingStopped), sender, e); } else { FinalizeWaveFile(); } } void StopRecord() { AllChangeBtn(btn_luyin, true); AllChangeBtn(btn_stop, false); AllChangeBtn(btn_sendsound, true); AllChangeBtn(btn_play, true); //btn_luyin.Enabled = true; //btn_stop.Enabled = false; //btn_sendsound.Enabled = true; //btn_play.Enabled = true; if (waveIn != null) waveIn.StopRecording(); //Cleanup(); } private void Cleanup() { if (waveIn != null) { waveIn.Dispose(); waveIn = null; } FinalizeWaveFile(); } private void FinalizeWaveFile() { if (writer != null) { writer.Dispose(); writer = null; } } //開始錄音 private void btn_luyin_Click(object sender, EventArgs e) { btn_stop.Enabled = true; btn_luyin.Enabled = false; if (waveIn == null) { CreateWaveInDevice(); } if (File.Exists(soundfile)) { File.Delete(soundfile); } writer = new WaveFileWriter(soundfile, waveIn.WaveFormat); waveIn.StartRecording(); }
語音傳送
當錄好音後,需要將錄好的檔案傳送出去,具體的實現程式碼如下所示:
如上面程式碼所示,我們就把產生的語音檔案傳送出去了,傳送端的處理結束。MsgTranslator tran = null; public Form1() { InitializeComponent(); LoadWasapiDevicesCombo();//顯示音訊裝置 Config cfg = SeiClient.GetDefaultConfig(); cfg.Port = 7777; UDPThread udp = new UDPThread(cfg); tran = new MsgTranslator(udp, cfg); tran.MessageReceived += tran_MessageReceived; tran.Debuged += new EventHandler<DebugEventArgs>(tran_Debuged); } private void btn_sendsound_Click(object sender, EventArgs e) { if (t_ip.Text == "") { MessageBox.Show("請輸入ip"); return; } if (t_port.Text == "") { MessageBox.Show("請輸入埠號"); return; } string ip = t_ip.Text; int port = int.Parse(t_port.Text); string nick = t_nick.Text; string msg = "語音訊息"; IPEndPoint remote = new IPEndPoint(IPAddress.Parse(ip), port); Msg m = new Msg(remote, "zz", nick, Commands.SendMsg, msg, "Come From A"); m.IsRequireReceive = true; m.ExtendMessageBytes = FileContent(soundfile); m.PackageNo = Msg.GetRandomNumber(); m.Type = Consts.MESSAGE_BINARY; tran.Send(m); } private byte[] FileContent(string fileName) { FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); try { byte[] buffur = new byte[fs.Length]; fs.Read(buffur, 0, (int)fs.Length); return buffur; } catch (Exception ex) { return null; } finally { if (fs != null) { //關閉資源 fs.Close(); } } }
語音的接收與播放
語音的接收和文字訊息的接收沒有什麼不同,只不過語音傳送的時候是以二進位制傳送的,因此我們在收到語音後 就應該寫入到一個檔案裡面去,接收完成後,播放這段語音就行了。
下面這段程式碼主要是把收到的資料儲存到檔案中去,這個函式式我的NetFrame裡收到訊息時所觸發的事件,在文章前面提過的那篇文章裡。
void tran_MessageReceived(object sender, MessageEventArgs e) { Msg msg = e.msg; if (msg.Type == Consts.MESSAGE_BINARY) { string m = msg.Type + "->" + msg.UserName + "發來二進位制訊息!"; AddServerMessage(m); if (File.Exists(recive_soundfile)) { File.Delete(recive_soundfile); } FileStream fs = new FileStream(recive_soundfile, FileMode.Create, FileAccess.Write); fs.Write(msg.ExtendMessageBytes, 0, msg.ExtendMessageBytes.Length); fs.Close(); //play_sound(recive_soundfile); ChangeBtn(true); } else { string m = msg.Type + "->" + msg.UserName + "說:" + msg.NormalMsg; AddServerMessage(m); } }
收到語音訊息後,我們要進行播放,播放時仍然用剛才那個外掛播放,具體的實現程式碼如下所示:
//--------播放部分----------
private IWavePlayer wavePlayer;
private WaveStream reader;
public void play_sound(string filename)
{
if (wavePlayer != null)
{
wavePlayer.Dispose();
wavePlayer = null;
}
if (reader != null)
{
reader.Dispose();
}
reader = new MediaFoundationReader(filename, new MediaFoundationReader.MediaFoundationReaderSettings() { SingleReaderObject = true });
if (wavePlayer == null)
{
wavePlayer = new WaveOut();
wavePlayer.PlaybackStopped += WavePlayerOnPlaybackStopped;
wavePlayer.Init(reader);
}
wavePlayer.Play();
}
private void WavePlayerOnPlaybackStopped(object sender, StoppedEventArgs stoppedEventArgs)
{
if (stoppedEventArgs.Exception != null)
{
MessageBox.Show(stoppedEventArgs.Exception.Message);
}
if (wavePlayer != null)
{
wavePlayer.Stop();
}
btn_luyin.Enabled = true;
}private void btn_play_Click(object sender, EventArgs e)
{
btn_luyin.Enabled = false;
play_sound(soundfile);
}
介面展示:
技術總結
整個系統實現的過程中,主要用到的技術就是UDP和NAudio的錄音和播放功能,其中用到的UDP傳輸類我放在了github上面 地址在我的部落格左邊的個人介紹裡有地址 專案地址 https://github.com/zhujunxxxxx/ZZNetFrame,希望這篇文章能夠提供一個思路。
相關推薦
基於UDP協議實現P2P語音聊天系統(C#版本)
原創性申明概述基於事件模型的UDP通訊框架(適用於網路包編解碼)】已經實現過了UDP的分包傳送資料的功能,而這篇文章主要是一個應用,使用UDP協議傳送語音和文字等資訊。在這個系統中沒有服務端和客戶端,相互通訊都是直接相互聯絡的,能夠很好的實現效果。具體實現1、語言資料來源獲取
Linux下基於UDP協議實現的聊天室專案(附原始碼)
好久沒來更新了,這段時間一直在著手完成這個專案,由於之前沒有接觸過這種稍大型的專案,而且對於C/S架構以及UDP通訊的瞭解也不是很深,所以前面很大的一段時間都被浪費掉了,做了很大無用功。 剛開始弄的時候,也是在網上搜了很多資料,找了很多版本,發現大都有
c#基於udp實現的p2p語音聊天工具
initial lis combobox pre cat microsoft user eat let 原創性申明 此博文的出處 為?http://blog.csd
基於UDP協議簡單聊天
code serve from pri true soc udp協議 bsp nbsp server端 import socket sk = socket.socket(type=socket.SOCK_DGRAM) sk.bind((‘127.0.0.1‘,8080)
UDP協議實現聊天小程式
今天我們用之前講解過的UDP協議來寫一個最基礎,最簡單的網路聊天程式。 //我們通過udp協議來實現一個簡單的網路聊天程式 //這是客戶端的實現 //過程: // 1.建立套接字 // 2.繫結地址資訊 // 3.向服務端傳送資料 // 4.接
JAVA——基於UDP協議的文字聊天程式
基於UDP協議的文字聊天程式 1.要求 使用JAVA完成一個基於TCP協議的文字聊天程式,建立TCP客戶端套接字,分別為服務端和客戶端,並使兩端可以互聯。 2.UDP協議 在UDP協議中,沒有TCP中所謂的伺服器端和客戶端,而是有資料的傳送端和接收端。也就是說UDP
基於udp協議的字串計數【網路程式設計 - 基於udp協議的字串計數,C實現】
udp_server.c #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") typedef struct sockaddr_in sockaddr_in ; typedef s
如何使用 Python 編寫基於 UDP 協議的聊天工具
import socket from sys import exit s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) HOST = '10.1.73.12' PORT = 10888 s.bind((HOST, PORT)) while Tru
語音識別——基於深度學習的中文語音識別系統實現(程式碼詳解)
文章目錄 利用thchs30為例建立一個語音識別系統 1. 特徵提取 2. 模型搭建 搭建cnn+dnn+ctc的聲學模型 3. 訓練準備 下載資料
基於pjsip實現p2p語音對講
目的 為實現跨網路的語音對講,使位於NAT後的兩個裝置進行p2p的語音通訊,此處選用pjsip開源專案來實現。 未解決的問題:對稱型的NAT無法實現p2p打洞,pjsip採用turn服務進行轉發,不能稱之為純粹的p2p。 pjisp簡介 PJSIP是
Socket網路程式設計(二)UDP協議實現聊天工具
package UDP_chat; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.List; import java.awt.Panel; import java.awt.TextField; import jav
15.基於UDP協議的聊天室程式
使用UDP協議完成一個聊天室程式的小專案,大部分程式碼都有註釋,一看就能看到的. 實現的功能: (1)檢視/顯示已經登陸的使用者資訊 (2)向已登陸的使用者傳送訊息 (3)輸出錯誤訊息,給
基於UDP協議的Socket程式設計——使用Socket程式設計實現客戶諮詢
利用UDP通訊的兩個端點是平等的,也就是說通訊的兩個程式關係是對等的,沒有主次之分,甚至它們的程式碼都可以完全一致,這一點要與基於TCP協議的Socket程式設計區分開來。 步驟: 1、利用DatagramPacket物件封裝資料包。 2、利用DatagramSocke
一個簡單的基於udp協議的聊天程式
下面,我就介紹一下我開發的一個使用udp協議的網路通訊程式、 程式的要求非常簡單,就是當我們知道對方的ip地址後,我們可以通過命令列輸入對方的ip地址,就可以向對方傳送文字資訊。 程式的使用方式:由命令列開啟程式,命令列有一個可選的引數,即你想要通訊的目標的ip地址(首先要
廣電系統衛星信號ASI數據轉成UDP協議流進入流媒體系統互聯網分發
ASI UDP RTMP 流媒體系統 ASI:傳輸的是數字信號,壓縮視頻信號(例如MPEG2-T,裏面是H.264碼流),用於廣播電視領域。 在目前的DVB-C系統設備的傳輸接口有兩種MPEG2視頻碼流傳輸接口標準:異步串行接口ASI和同步並行接口SPI。本文
基於UDP協議的socket編程
tcp server end 註意 發出 發生 數據報 無連接 允許 UDP協議特點: 1.無連接。服務端與客戶端傳輸數據之前不需要進行連接,且沒有超時重發等機制,只是把數據通過網絡發送出去。也正是因為此特點,所以基於UDP協議的socket的客戶端在啟動之前不需要先啟
Python--網絡編程-----基於UDP協議的套接字
data soc nbsp net 服務 int ddr bind 客戶 服務端: 1 from socket import * 2 3 server = socket(AF_INET, SOCK_DGRAM) 4 server.bind((‘127.0.0.1
Java學習總結(十三)——基於UDP協議網絡編程
網絡編程 UDP協議 聊天 一.UDP網絡編程1.面向無連接的數據傳輸,不可靠的,但效率高(音頻,視頻等).2.UDP一次發送的數據不能超過64kb.3.UDP編程所需要的類(1)DatagramSocket此類表示用來發送和接收數據報包的套接字(2)DatagramPacket此類表示數據報包方
基於UDP協議的網絡程序
UDP socket下圖是基於UDP協議的客戶端/服務器程序的一般流程:圖1.1 UDP協議通信流程UDP套接口是無連接的、不可靠的數據報協議;既然他不可靠為什麽還要用呢?其一:當應用程序使用廣播或多播時只能使用UDP協議;其二:由於他是無連接的,所以速度快。因為UDP套接口是無連接的,如果一方的數據報丟失,
網絡編程之基於UDP協議套接字
本質 系統內存 現象 服務 自身 png 收發消息 accept color 1.UDP協議介紹(數據報協議) UDP協議不同於TCP,通信時,它不需要事先建立雙向鏈接,並且不區分客戶端先啟動還是服務端前起,工作原理:基於udp協議傳輸的信息,協議會將數據自動加上自定義