程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#基於UDP完成的P2P語音聊天對象

C#基於UDP完成的P2P語音聊天對象

編輯:C#入門知識

C#基於UDP完成的P2P語音聊天對象。本站提示廣大學習愛好者:(C#基於UDP完成的P2P語音聊天對象)文章只能為提供參考,不一定能成為您想要的結果。以下是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語音聊天對象。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved