2011-01-27 4 views
4

here 코드를 사용하여 마이크에서 오디오를 전송할 수있었습니다.Nothing을 사용하여 오디오 재생

그러나 NAudio을 사용하여이 작업을 수행 할 수 없었습니다.

G711.Encode_aLaw 
G711.Decode_uLaw 

번역 및 네트워크를 통해 전송할 바이트를 반환 :

CodeProject의에서 코드는 다음과 같은 명시 적으로 인코딩 코드 및 디코드 있습니다.

위의 CodeProject 응용 프로그램에 대한 NAudio에 대한 샘플 코드를 얻을 수 있습니까?

답변

0

다음은 u-Law 또는 A-Law 인코딩을 사용하여 NAudio, 마이크 입력, 스피커 출력을 사용하여 작성한 빠른 C# 콘솔 응용 프로그램입니다. NAudio.Codecs 네임 스페이스에는 A-Law 및 u-Law 인코더와 디코더가 포함되어 있습니다.

이 프로그램은 이 아니며은 네트워크를 통해 데이터를 전송합니다 (어렵지는 않지만 여기에서하는 것처럼 느껴지지 않았습니다). 나는 너에게 맡길거야. 대신 "보낸 사람"스레드와 "받는 사람"스레드가 있습니다.

마이크로폰 DataAvailable 이벤트 핸들러는 바이트 버퍼를 큐에 놓습니다 (버퍼의 사본을 만듭니다 - 이벤트의 실제 버퍼를 보유하고 싶지는 않습니다). "Sender"스레드는 대기중인 버퍼를 가져 와서 PCM 데이터를 g.711로 변환하고 두 번째 대기열에 놓습니다. 이 "두 번째 대기열로 빠져라"부분은 특정 응용 프로그램의 원격 UDP 대상으로 전송하는 부분입니다.

"수신자"스레드는 두 번째 대기열에서 데이터를 읽고 다시 PCM으로 변환 한 다음 WaveOut (스피커) 장치에서 사용중인 BufferedWaveProvider으로 전송합니다. 이 입력을 네트워크 응용 프로그램의 UDP 소켓 수신으로 바꿉니다.

PCM 입출력 (마이크 및 스피커)이 동일한 WaveFormat을 사용한다는 것을 보증합니다. 네트워크화 된 엔드 포인트를 위해해야 ​​할 일이기도합니다.

어쨌든 작동합니다. 여기 코드가 있습니다. 나는 너무 자세하게 설명하지 않을 것이다. 진행 상황을 이해하는 데 도움이되는 많은 의견이 있습니다.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using NAudio.Wave; 
using NAudio.Codecs; 

namespace G711MicStream 
{ 
    class Program 
    { 
     delegate byte EncoderMethod(short _raw); 
     delegate short DecoderMethod(byte _encoded); 

     // Change these to their ALaw equivalent if you want. 
     static EncoderMethod Encoder = MuLawEncoder.LinearToMuLawSample; 
     static DecoderMethod Decoder = MuLawDecoder.MuLawToLinearSample; 



     static void Main(string[] args) 
     { 
      // Fire off our Sender thread. 
      Thread sender = new Thread(new ThreadStart(Sender)); 
      sender.Start(); 

      // And receiver... 
      Thread receiver = new Thread(new ThreadStart(Receiver)); 
      receiver.Start(); 

      // We're going to try for 16-bit PCM, 8KHz sampling, 1 channel. 
      // This should align nicely with u-law 
      CommonFormat = new WaveFormat(16000, 16, 1); 

      // Prep the input. 
      IWaveIn wavein = new WaveInEvent(); 
      wavein.WaveFormat = CommonFormat; 
      wavein.DataAvailable += new EventHandler<WaveInEventArgs>(wavein_DataAvailable); 
      wavein.StartRecording(); 

      // Prep the output. The Provider gets the same formatting. 
      WaveOut waveout = new WaveOut(); 
      OutProvider = new BufferedWaveProvider(CommonFormat); 
      waveout.Init(OutProvider); 
      waveout.Play(); 


      // Now we can just run until the user hits the <X> button. 
      Console.WriteLine("Running g.711 audio test. Hit <X> to quit."); 
      for(; ;) 
      { 
       Thread.Sleep(100); 
       if(!Console.KeyAvailable) continue; 
       ConsoleKeyInfo info = Console.ReadKey(false); 
       if((info.Modifiers & ConsoleModifiers.Alt) != 0) continue; 
       if((info.Modifiers & ConsoleModifiers.Control) != 0) continue; 

       // Quit looping on non-Alt, non-Ctrl X 
       if(info.Key == ConsoleKey.X) break;     
      } 

      Console.WriteLine("Stopping..."); 

      // Shut down the mic and kick the thread semaphore (without putting 
      // anything in the queue). This will (eventually) stop the thread 
      // (which also signals the receiver thread to stop). 
      wavein.StopRecording(); 
      try{ wavein.Dispose(); } catch(Exception){} 
      SenderKick.Release(); 

      // Wait for both threads to exit. 
      sender.Join(); 
      receiver.Join(); 

      // And close down the output. 
      waveout.Stop(); 
      try{ waveout.Dispose(); } catch(Exception) {} 

      // Sleep a little. This seems to be accepted practice when shutting 
      // down these audio components. 
      Thread.Sleep(500); 
     } 


     /// <summary> 
     /// Grabs the mic data and just queues it up for the Sender. 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     static void wavein_DataAvailable(object sender, WaveInEventArgs e) 
     { 
      // Create a local copy buffer. 
      byte [] buffer = new byte [e.BytesRecorded]; 
      System.Buffer.BlockCopy(e.Buffer, 0, buffer, 0, e.BytesRecorded); 

      // Drop it into the queue. We'll need to lock for this. 
      Lock.WaitOne(); 
      SenderQueue.AddLast(buffer); 
      Lock.ReleaseMutex(); 

      // and kick the thread. 
      SenderKick.Release(); 
     } 


     static 
     void 
     Sender() 
     { 
      // Holds the data from the DataAvailable event. 
      byte [] qbuffer = null; 

      for(; ;) 
      { 
       // Wait for a 'kick'... 
       SenderKick.WaitOne(); 

       // Lock... 
       Lock.WaitOne(); 
       bool dataavailable = (SenderQueue.Count != 0); 
       if(dataavailable) 
       { 
        qbuffer = SenderQueue.First.Value; 
        SenderQueue.RemoveFirst(); 
       } 
       Lock.ReleaseMutex(); 

       // If the queue was empty on a kick, then that's our signal to 
       // exit. 
       if(!dataavailable) break; 

       // Convert each 16-bit PCM sample to its 1-byte u-law equivalent. 
       int numsamples = qbuffer.Length/sizeof(short); 
       byte [] g711buff = new byte [numsamples]; 

       // I like unsafe for this kind of stuff! 
       unsafe 
       { 
        fixed(byte * inbytes = &qbuffer[0]) 
        fixed(byte * outbytes = &g711buff[0]) 
        { 
         // Recast input buffer to short[] 
         short * buff = (short *)inbytes; 

         // And loop over the samples. Since both input and 
         // output are 16-bit, we can use the same index. 
         for(int index = 0; index < numsamples; ++index) 
         { 
          outbytes[index] = Encoder(buff[index]); 
         } 
        } 
       } 

       // This gets passed off to the reciver. We'll queue it for now. 
       Lock.WaitOne(); 
       ReceiverQueue.AddLast(g711buff); 
       Lock.ReleaseMutex(); 
       ReceiverKick.Release(); 
      } 

      // Log it. We'll also kick the receiver (with no queue addition) 
      // to force it to exit. 
      Console.WriteLine("Sender: Exiting."); 
      ReceiverKick.Release(); 
     } 

     static 
     void 
     Receiver() 
     { 
      byte [] qbuffer = null; 
      for(; ;) 
      { 
       // Wait for a 'kick'... 
       ReceiverKick.WaitOne(); 

       // Lock... 
       Lock.WaitOne(); 
       bool dataavailable = (ReceiverQueue.Count != 0); 
       if(dataavailable) 
       { 
        qbuffer = ReceiverQueue.First.Value; 
        ReceiverQueue.RemoveFirst(); 
       } 
       Lock.ReleaseMutex(); 

       // Exit on kick with no data. 
       if(!dataavailable) break; 

       // As above, but we convert in reverse, from 1-byte u-law 
       // samples to 2-byte PCM samples. 
       int numsamples = qbuffer.Length; 
       byte [] outbuff = new byte [qbuffer.Length * 2]; 
       unsafe 
       { 
        fixed(byte * inbytes = &qbuffer[0]) 
        fixed(byte * outbytes = &outbuff[0]) 
        { 
         // Recast the output to short[] 
         short * outpcm = (short *)outbytes; 

         // And loop over the u-las samples. 
         for(int index = 0; index < numsamples; ++index) 
         { 
          outpcm[index] = Decoder(inbytes[index]); 
         } 
        } 
       } 

       // And write the output buffer to the Provider buffer for the 
       // WaveOut devices. 
       OutProvider.AddSamples(outbuff, 0, outbuff.Length); 
      } 

      Console.Write("Receiver: Exiting."); 
     } 


     /// <summary>Lock for the sender queue.</summary> 
     static Mutex Lock = new Mutex(); 

     static WaveFormat CommonFormat; 

     /// <summary>"Kick" semaphore for the sender queue.</summary> 
     static Semaphore SenderKick = new Semaphore(0, int.MaxValue); 
     /// <summary>Queue of byte buffers from the DataAvailable event.</summary> 
     static LinkedList<byte []> SenderQueue = new LinkedList<byte[]>(); 

     static Semaphore ReceiverKick = new Semaphore(0, int.MaxValue); 
     static LinkedList<byte []> ReceiverQueue = new LinkedList<byte[]>(); 

     /// <summary>WaveProvider for the output.</summary> 
     static BufferedWaveProvider OutProvider; 
    } 
}