c#基于udp实现的p2p语音聊天工具

原创 2014年10月16日 00:04:01

原创性申明

此博文的出处 为 http://blog.csdn.net/zhujunxxxxx/article/details/40124773如果进行转载请注明出处。本文作者原创,邮箱zhujunxxxxx@163.com,如有问题请联系作者

概述

之前发过一篇文章http://blog.csdn.net/zhujunxxxxx/article/details/38864817 已经实现过了UDP的分包发送数据的功能,而这篇文章主要是一个应用,使用udp传送语音和文本等信息。在这个系统中没有服务端和客户端,相互通讯都是直接相互联系的。能够很好的实现效果。

语音获取

要想发送语音信息,首先得获取语音,这里有几种方法,一种是使用DirectX的DirectXsound来录音,我为了简便使用一个开源的插件NAudio来实现语音录取。 在项目中引用NAudio.dll

//------------------录音相关-----------------------------
        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();
        }




上面的代码实现了录音,并且写入文件p2psound_A.wav

语音发送

获取到语音后我们要把语音发送出去

当我们录好音后点击发送,这部分相关代码是

 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

希望这篇文章能够提供一个思路。


更新程序下载地址 http://download.csdn.net/detail/zhujunxxxxx/8061125 很好的代码,希望大家喜欢


C#实现语音聊天之DirectX方法

[声明:本篇来源:http://www.cnblogs.com/stg609/archive/2008/11/19/1334544.html 作者:stg609]       现在时下的VOIP软件...

Unity5.x实现简易语音聊天(二) 录音与播放

0. 背景上一文(一)使用步骤,以下称(一)讲述如何使用既有材料和Unity5.x,构建一个简单的语音聊天客户端,服务端程序。本文会详细讲述语音聊天的框架流程和客户端录音和播放相关组件的API。...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

C#实现多人视频聊天

视频聊天室,或多人视频聊天,是即时通信应用中常见的功能之一,比如,QQ的视频讨论组就是我们用得比较多的。这篇文章将实现一个简单的视频聊天室,让多个人可以进入同一个房间进行语音视频交谈。...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

C#中利用Socket实现网络语音通信[初级版本]

现在时下的VOIP软件很多,比较有名的就是Skype,还有其它诸如UUcall、快门等等。它们提供的功能除了网络上的语音通话外,还可以与固定电话、手机等通话。在本篇中主要介绍利用C#实现语音通信的基本...

java 语言写的语音聊天程序

java 语言写的语音聊天程序 受朋友之托,写了一个小的语音聊天程序,不敢独享,写出来供大家分享! 由于在上大学的时候,老师曾经教我们做过一个聊天程序,再说网络上的资料这么丰富,所以当时       ...

【腾讯TMQ】漫步VR——Unity语音聊天室开发小结

2016年被业内称为VR元年,各大VR硬件百花齐放。VR到底是什么?如何尝试在三大VR平台之一的Oculus研发自己的VR应用?本文step by step的详细介绍,实战演练,干货满满!...
  • TMQ1225
  • TMQ1225
  • 2016年09月01日 14:41
  • 893
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:c#基于udp实现的p2p语音聊天工具
举报原因:
原因补充:

(最多只允许输入30个字)