C#基于UDP实现的P2P语音聊天工具

语音获取

要想发送语音信息,首先得获取语音,这里有几种方法,一种是使用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;
ublic 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的录音和播放功能

希望这篇文章能够给大家提供一个思路,帮助大家实现P2P语音聊天工具。

(0)

相关推荐

  • C#制作简单的多人在线即时交流聊天室

    实现网页版的在线聊天室的方法有很多,在没有来到HTML5之前,常见的有:定时轮询.长连接+长轮询.基于第三方插件(如FLASH的Socket),而如果是HTML5,则比较简单,可以直接使用WebSocket,当然HTML5目前在PC端并没有被所有浏览器支持,所以我的这个聊天室仍是基于长连接+长轮询+原生的JS及AJAX实现的多人在线即时交流聊天室,这个聊天室其实是我上周周末完成的,功能简单,可能有些不足,但可以满足在线即时聊天需求,分享也是给大家提供一个思路,大家可以基于此来实现更好的在线即时聊

  • c#多线程网络聊天程序代码分享(服务器端和客户端)

    XuLIeHua类库 复制代码 代码如下: using System;using System.Collections;  using System.Collections.Generic;using System.Threading;  using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;using System.Text;using System.IO;using Sy

  • C#基于Windows服务的聊天程序(1)

    本文将演示怎么通过C#开发部署一个Windows服务,该服务提供各客户端的信息通讯,适用于局域网.采用TCP协议,单一服务器连接模式为一对多:多台服务器的情况下,当客户端连接数超过预设值时可自动进行负载转移,当然也可手动切换服务器,这种场景在实际项目中应用广泛. 简单的消息则通过服务器转发,文件类的消息则让客户端自己建立连接进行传输.后续功能将慢慢完善. 自定义协议: 1.新建Windows服务项目 2.修改配置文件添加 <appSettings> <add key="maxQ

  • C#聊天程序服务端与客户端完整实例代码

    本文所述为基于C#实现的多人聊天程序服务端与客户端完整代码.本实例省略了结构定义部分,服务端主要是逻辑处理部分代码,因此使用时需要完善一些窗体按钮之类的. 先看服务端代码如下: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Net; using

  • 分享一个C#编写简单的聊天程序(详细介绍)

    引言 这是一篇基于Socket进行网络编程的入门文章,我对于网络编程的学习并不够深入,这篇文章是对于自己知识的一个巩固,同时希望能为初学的朋友提供一点参考.文章大体分为四个部分:程序的分析与设计.C#网络编程基础(篇外篇).聊天程序的实现模式.程序实现. 程序的分析与设计 1.明确程序功能 如果大家现在已经参加了工作,你的经理或者老板告诉你,"小王,我需要你开发一个聊天程序".那么接下来该怎么做呢?你是不是在脑子里有个雏形,然后就直接打开VS2005开始设计窗体,编写代码了呢?在开始之

  • c#实现多线程局域网聊天系统

    觉得好有点帮助就顶一下啦. socke编程,支持多客户端,多线程操作避免界面卡死. 开启socket private void button1_Click(object sender, EventArgs e) { try { int port = int.Parse(txt_port.Text); string host = txt_ip.Text; //创建终结点 IPAddress ip = IPAddress.Parse(host); IPEndPoint ipe = new IPEnd

  • 基于c#用Socket做一个局域网聊天工具

    程序设计成为简单的服务端和客户端之间的通信, 但通过一些方法可以将这两者进行统一起来, 让服务端也成为客户端, 让客户端也成为服务端, 使它们之间可以互相随时不间断的通信. 考虑到实现最原始的服务端和客户端之间的通信所需要的步骤对于写这样的程序是很有帮助的. 作为服务端, 要声明一个Socket A并绑定(Bind)某一个IP+这个IP指定的通信端口, 比如这个是127.0.0.1:9050, 然后开始监听(Listen), Listen可以监听来自多个IP传过来的连接请求, 具体可以同时连接几

  • C#实现简单聊天程序的方法

    本文实例讲述了C#简单聊天程序实现方法.分享给大家供大家参考.具体如下: 假如有服务器端程序,ChatServer和客户端程序ChatClient.实现客户端向服务器端发送信息的简单功能. 运行步骤, 1.先是服务器端start listen, 2.然后客户端connect. 3.客户端发送消息   只要服务器端start listen了,然后客户端也connect了.这样建立起连接后.接受发送信息就方便了,只要用writer,reader去操作NetworkStream   服务器ChatSe

  • C#基于UDP实现的P2P语音聊天工具

    语音获取 要想发送语音信息,首先得获取语音,这里有几种方法,一种是使用DirectX的DirectXsound来录音,我为了简便使用一个开源的插件NAudio来实现语音录取. 在项目中引用NAudio.dll //------------------录音相关----------------------------- private IWaveIn waveIn; private WaveFileWriter writer; private void LoadWasapiDevicesCombo(

  • Java基于UDP协议实现简单的聊天室程序

    最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆. 先看一下效果: 实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理.  "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着. 看一下代码实现: 1.首先是消息服务器的实现,功能很简单: •将客户端的信息(进入了哪一

  • java网络之基于UDP的聊天程序示例解析

    基于UDP的Socket通信 UDP协议不是一种基于稳定连接的协议,是一种面向数据报包的通信协议,不需要通信双方建立稳定的连接,也没有所谓服务端和客户的概念,数据报包在传输的时候不保证一定及时到达,也不能保证数据报包的到达顺序,但是UDP协议传输效率要远高于TCP/IP. 以下是一个基于UDP的简单的消息发送接收程序. 消息发送方 1.创建一个数据报的网络通道 DatagramSocket ds = new DatagramSocket(); 2.准备需要传输的数据 String msg = "

  • java实现基于UDP协议的聊天小程序操作

    UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议.它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去! UDP适用于一次只传送少量数据.对可靠性要求不高的应用环境.正因为UDP协议没有连接的过程,所以它的通信效率高:但也正因为如此,它的可靠性不如TCP协议高.QQ就使用UDP发消息,因此有时会出现收不到消息的情况. 利用UDP协议的发送和接收,模拟聊天小程序 创建聊天程序的A端: 1.发送信息到接收端                 1 .准

  • java基于UDP实现在线聊天功能

    本文实例为大家分享了java基于UDP实现在线聊天的具体代码,供大家参考,具体内容如下 效果图: 一.学习UDP的简单使用步骤 接收端: DatagramSocket socket = null;         try {             //1.开启自己的端口(客户端连接的端口)             socket = new DatagramSocket(9999);             //2.接收数据             byte[] buffer = new byt

  • Java基于UDP协议的聊天室功能

    UDP简述 UDP(User Datagram Protocol)协议是Internet 协议集支持的一个无连接的传输协议,中文名为用户数据报协议.它为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法. Internet 的传输层有两个主要协议,互为补充.无连接的是 UDP,它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情.面向连接的是TCP,该协议几乎做了所有的事情.“when in trouble , use TCP”. 那

  • c# 实现语音聊天的实战示例

    一.语音聊天说专业点就是即时语音,是一种基于网络的快速传递语音信息的技术,普遍应用于各类社交软件中,优势主要有以下几点: (1)时效性:视频直播会因为带宽问题有时出现延迟高的问题,而语音直播相对来说会好很多,延迟低,并且能够第·一时间与听众互动,时效性强. (2)隐私性:这一点体现在何处,如主播不想暴露自己的长相,或者进行问题回答是,没有视频的话会让主播感到更安心,所以语音直播隐私性更强. (3)内容质量高:因为语音直播不靠"颜值"只有好的内容才能够吸引用户,所以语音直播相对来说内容质

  • 基于Swoole实现PHP与websocket聊天室

    websocket Websocket只是一个网络通信协议 就像 http.ftp等都是网络通信的协议:不要多想: 相对于HTTP这种非持久的协议来说,Websocket是一个持久化网络通信的协议: WebSocket和HTTP的关系 有交集,但是并不是全部. Websocket只是借用了HTTP的一部分协议来完成一次握手.(HTTP的三次握手,此处只完成一次) http和websocket 请求头对比: HTTP: 原来的时候,客户端通过http(骑马)带着信请求服务器,服务器处理请求(写回信

  • 在Ubuntu上搭建一个基于webrtc的多人视频聊天服务实例代码详解

    WebRTC,即Web Real-Time Communication,web实时通信技术.简单地说就是在web浏览器里面引入实时通信,包括音视频通话等. 在疫情期间哪里也去不了,在家没事就研究webrtc视频直播技术,网上找了些教程最终都不太能顺利跑起来的,可能是文章写的比较老,使用的一些开源组件已经更新了,有些配置已经不太一样了,所以按照以前的步骤会有问题.折腾了一阵终于跑起来了,记录一下. 一个简单的聊天室html页面 这个页面使用simple-webrtc来实现webrtc的通讯,sim

  • java实现基于UDP协议网络Socket编程(C/S通信)

    一.前言:认识UDP UDP,全称User Datagram Protocol(用户数据报协议),是Internet 协议集支持一个无连接的传输协议.UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法. UDP主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成,提供面向报文的简单不可靠信息传送服务.UDP 协议基本上是IP协议与上层协议的接口,适用端口分别运行在同一台设备上的多个应用程序. 二.UDP的特点(与TCP相比) 正是UDP提供不可靠服务

随机推荐