在網絡聊天系統中,採集麥克風的聲音並將其播放出來,是最基礎的模塊之一。本文咱們就介紹如何快速地實現這個基礎模塊。網絡
有幾個與聲音採集和播放相關的專業術語必需要先了解一下,不然,後面的介紹將沒法展開。語音採集指的是從麥克風採集音頻數據,即聲音樣本轉換成數字信號。其涉及到幾個重要的參數:採樣率、採樣位數、聲道數。this
簡單的來講:編碼
採樣率:即採樣頻率,就是在1秒內進行採集動做的次數。spa
採樣位數:又叫採樣深度,就是每次採集動做獲得的數據長度,即便用多少個bit來記錄一個樣本。3d
聲道數:通常是單聲道或雙聲道(立體聲)。普通的麥克風採集幾乎都是單聲道的。code
這樣,1秒鐘採集獲得的聲音數據的大小爲(單位byte):(採樣頻率×採樣位數×聲道數×時間)/8。orm
音頻幀:一般一個音頻幀的時長爲10ms,即每10ms的數據構成一個音頻幀。假設:採樣率16k、採樣位數16bit、聲道數1,那麼一個10ms的音頻幀的大小爲:(16000*16*1*0.01)/8 = 320 字節。計算式中的0.01爲秒,即10msblog
若是直接基於底層的DirectX來進行麥克風的採集與播放,那將是十分繁瑣的。好在咱們有現成的組件來完成這個工做,MCapture用於採集硬件設備(如麥克風、攝像頭、聲卡、屏幕等),MPlayer用於播放採集到的數據。事件
1.採集麥克風get
MCapture提供了IMicrophoneCapturer,用於採集麥克風輸入的聲音。其每隔20ms觸發一次AudioCaptured事件,經過事件的參數byte[]暴露這20ms採集獲得的數據。
IMicrophoneCapturer 相關採集參數的值是這樣的:
採樣頻率:16000,採樣位數:16bit,聲道數:1。
因此,按照上面的公式進行計算,咱們能夠獲得AudioCaptured事件的參數byte[]的長度爲640。
2. 播放聲音數據
MPlayer提供了IAudioPlayer,用於播放聲音數據。在建立IAudioPlayer實例時,要正確的設置採樣頻率、採樣位數、聲道數這些參數的值,若是它們與即將要播放的聲音數據的特徵不一致,播放將出現錯誤。
咱們在拿到MCapture採集的聲音數據後,將其提交給IAudioPlayer的Play方法進行播放便可。
在有了前面的介紹做爲基礎後,接下來實現麥克風的採集和播放就至關簡單了。在接下來的demo中,不只演示了播放從麥克風採集到的聲音,並且多加了一個功能,就是直接播放wav聲音文件,這些實現都是至關簡單的。
public partial class Form1 : Form { private IAudioPlayer audioPlayer; private IMicrophoneCapturer microphoneCapturer; public Form1() { InitializeComponent(); } private void button_mic_Click(object sender, EventArgs e) { try { this.microphoneCapturer = CapturerFactory.CreateMicrophoneCapturer(int.Parse(this.textBox_mic.Text)); this.microphoneCapturer.AudioCaptured += new ESBasic.CbGeneric<byte[]>(microphoneCapturer_AudioCaptured); this.audioPlayer = PlayerFactory.CreateAudioPlayer(int.Parse(this.textBox_speaker.Text), 16000, 1, 16, 2); this.microphoneCapturer.Start(); this.label_msg.Text = "正在採集麥克風,並播放 . . ."; this.label_msg.Visible = true; this.button_wav.Enabled = false; this.button_mic.Enabled = false; this.button_stop.Enabled = true; } catch (Exception ee) { MessageBox.Show(ee.Message); } } void microphoneCapturer_AudioCaptured(byte[] audioData) { if (this.audioPlayer != null) { this.audioPlayer.Play(audioData); } } private void button_wav_Click(object sender, EventArgs e) { try { string path = ESBasic.Helpers.FileHelper.GetFileToOpen2("請選擇要播放的wav文件", AppDomain.CurrentDomain.BaseDirectory, ".wav"); if (path == null) { return; } AudioInformation info = PlayerFactory.ParseWaveFile(path); if (info.FormatTag != (int)WaveFormats.Pcm) { MessageBox.Show("僅僅支持PCM編碼方式的語音數據!"); return; } int secs = info.GetTimeInMsecs() / 1000; //聲音數據的播放時長 this.audioPlayer = PlayerFactory.CreateAudioPlayer(int.Parse(this.textBox_speaker.Text), info.SampleRate, info.ChannelCount, info.BitsNumber, secs + 1); this.audioPlayer.Play(info.AudioData); this.label_msg.Text = "正在播放wav文件 . . ."; this.label_msg.Visible = true; this.button_wav.Enabled = false; this.button_mic.Enabled = false; this.button_stop.Enabled = true; } catch (Exception ee) { MessageBox.Show(ee.Message); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (this.microphoneCapturer != null) { this.microphoneCapturer.Stop(); this.microphoneCapturer.Dispose(); this.microphoneCapturer = null; } if (this.audioPlayer != null) { this.audioPlayer.Dispose(); this.audioPlayer = null; } } private void button_stop_Click(object sender, EventArgs e) { if (this.audioPlayer == null) { return; } if (this.microphoneCapturer != null) { this.microphoneCapturer.Stop(); this.microphoneCapturer.Dispose(); this.microphoneCapturer = null; } this.audioPlayer.Clear(); this.audioPlayer.Dispose(); this.audioPlayer = null; this.label_msg.Visible = false; this.button_wav.Enabled = true; this.button_mic.Enabled = true; this.button_stop.Enabled = false; } }
看看demo運行的效果圖: