あなたが助けてくれることを願っています。マイクから音声を録音し、ネットワーク経由でライブ ストリーミングしています。サンプルの品質は 11025hz、8 ビット、モノラルです。わずかな遅延 (1 秒) がありますが、うまく機能します。私が助けを必要としているのは、ノイズリダクションと圧縮を実装して、オーディオをより静かにし、使用する帯域幅を少なくしようとしていることです。オーディオ サンプルは、Bytes[] の C# 配列に格納されており、Socket を使用して送受信しています。
C# で圧縮とノイズ削減を実装する方法を提案できる人はいますか? 無料(LGPL ライセンスなど)で C# から利用できるものであれば、サードパーティのライブラリを使用してもかまいません。ただし、実際に動作するソース コードの例の方が望ましいと思います。ご提案いただきありがとうございます。
アップデート:
ビット サイズを 8 ビット オーディオから 16 ビット オーディオに変更したところ、ノイズの問題が修正されました。明らかに、マイクからの 8 ビット オーディオの S/N 比が低すぎました。音声は 11khz、16 ビット モノで素晴らしく聞こえます。
ただし、これを投稿してから、このプロジェクトの要件が変更されました。現在、動画の追加も検討中です。ウェブカメラから 100 ミリ秒ごとにライブ画像を受信するコールバック設定があります。オーディオとビデオをエンコードし、それらを多重化し、ソケットでサーバーに送信する必要があります。サーバーはストリームを他のクライアントに再送信し、ストリームを受信し、ストリームを分離し、オーディオとビデオをデコードし、ビデオをピクチャボックスに出力し、オーディオをスピーカーに出力します。
(de|en)coding/[de]muxing を支援するために ffmpeg を検討しています。また、ffmpeg への C# 相互運用ライブラリとして SharpFFmpeg も検討しています。
これを行う良い例は見つかりません。私は 1 週間ずっとインターネットを探し回りましたが、まったく運がありませんでした。あなたが提供できるどんな助けも大歓迎です!
マイク録音用のコールバック関数を含むいくつかのコードを次に示します。
プライベート const int AUDIO_FREQ = 11025; プライベート const int CHANNELS = 1; プライベート const int BITS = 16; private const int BYTES_PER_SEC = AUDIO_FREQ * CHANNELS * (BITS / 8); プライベート const int BLOCKS_PER_SEC = 40; プライベート const int BUFFER_SECS = 1; private const int BUF_SIZE = ((int)(BYTES_PER_SEC / BLOCKS_PER_SEC * BUFFER_SECS / 2)) * 2; // 最も近い偶数に四捨五入 プライベート WaveLib.WaveOutPlayer m_Player; プライベート WaveLib.WaveInRecorder m_Recorder; プライベート WaveLib.FifoStream m_Fifo; ウェブカメラ MyWebCam; public void OnPickupHeadset() { stopRingTone(); m_Fifo = 新しい WaveLib.FifoStream(); WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(AUDIO_FREQ, BITS, CHANNELS); m_Player = 新しい WaveLib.WaveOutPlayer(-1, fmt, BUF_SIZE, BLOCKS_PER_SEC, new WaveLib.BufferFillEventHandler(PlayerCB)); m_Recorder = new WaveLib.WaveInRecorder(-1, fmt, BUF_SIZE, BLOCKS_PER_SEC, new WaveLib.BufferDoneEventHandler(RecorderCB)); MyWebCam = null; 試す { MyWebCam = 新しい WebCam(); MyWebCam.InitializeWebCam(ref pbMyPhoto, pbPhoto.Width, pbPhoto.Height); MyWebCam.Start(); } キャッチ { } } プライベート バイト[] m_PlayBuffer; private void PlayerCB(IntPtr data, int size) { 試す { if (m_PlayBuffer == null || m_PlayBuffer.Length != サイズ) m_PlayBuffer = 新しいバイト[サイズ]; if (m_Fifo.Length >= サイズ) { m_Fifo.Read(m_PlayBuffer, 0, サイズ); } そうしないと { // 読めるものを読む int fifoLength = (int)m_Fifo.Length; m_Fifo.Read(m_PlayBuffer, 0, fifoLength); // バッファの残りをゼロにする for (int i = fifoLength; i < m_PlayBuffer.Length; i++) m_PlayBuffer[i] = 0; } // 再生バッファを返す Marshal.Copy(m_PlayBuffer, 0, データ, サイズ); } キャッチ { } } プライベート バイト[] m_RecBuffer; private void RecorderCB(IntPtr データ、int サイズ) { 試す { if (m_RecBuffer == null || m_RecBuffer.Length != サイズ) m_RecBuffer = 新しいバイト[サイズ]; Marshal.Copy(データ、m_RecBuffer、0、サイズ); // 方法がわかれば、ここでオーディオをエンコードします // サーバーにデータを送信 if (theForm.CallClient != null) { SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.SetBuffer(m_RecBuffer, 0, m_RecBuffer.Length); theForm.CallClient.SendAsync(引数); } } キャッチ { } } //サーバー(他のクライアント)からデータを受信したときにネットワークスタックから呼び出される public void PlayBuffer(byte[] buffer, int length) { 試す { // 方法がわかれば、ここでオーディオをデコードします m_Fifo.Write(バッファ、0、長さ); } キャッチ { } }
では、ここからどこへ行けばよいのでしょうか。