using System; using System.Collections.Generic; using System.Text; using System.IO; using NAudio.Wave; using NSpeex; namespace SafeMobileLib { public class NSpeexVoiceClass { private IWaveIn waveIn; private IWavePlayer waveOut; private int INdeviceID, OUTdeviceID; private System.Threading.Timer tCheck; private bool waveOutisPlaying = false; public NSpeexVoiceClass(Mode m, int Q, int INdeviceID, int OUTdeviceID) { //Console.WriteLine("Voice started with NSpeex"); this.INdeviceID = INdeviceID; this.OUTdeviceID = OUTdeviceID; encoder = new NSpeex.Encoder(m); encoder.Quality = Q; encoder.VBR = true; preProcessor = new PreProcessor(encoder) { AGC = true, AGCIncrement = 3, Denoise = true, VAD = true }; //Console.WriteLine(encoder.FrameSize*50); waveFormat = new NAudio.Wave.WaveFormat(encoder.FrameSize * 50, 16, 1); waveIn = new WaveIn(WaveCallbackInfo.FunctionCallback()) { WaveFormat = waveFormat,BufferMilliseconds= 20, NumberOfBuffers = 2,DeviceNumber = INdeviceID }; waveIn.DataAvailable += waveIn_DataAvailable; waveIn.RecordingStopped += waveIn_RecordingStopped; //waveProvider = new BufferedWaveProvider(); waveProvider = new JitterBufferWaveProvider(m); waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()) {DeviceNumber = OUTdeviceID }; waveProvider.VolumeUpdated += new EventHandler(waveProvider_StreamVolume); waveOut.Init(waveProvider); //waveOut.Init(new WaveMixerStream32()); waveOut.Volume = 1.0f; } void waveProvider_StreamVolume(object sender, VolumeUpdatedEventArgs e) { if (OnStreamVolume != null) { OnStreamVolume(e.Volume); } } public void Start() { try { waveIn.StartRecording(); IsRecording = true; tCheck = new System.Threading.Timer(Check, null, new TimeSpan(0, 0, 0, 0, 0), new TimeSpan(0, 0, 0, 0, 200)); waveOut.Play(); } catch (Exception ex) { SM.Debug("Unable to start audio device"); Console.WriteLine(ex.ToString()); } } public void Stop() { try { waveIn.StopRecording(); tCheck.Dispose(); if (waveOut != null) { //waveOut.Stop(); //waveOut = null; //waveOut.Dispose(); } } catch (Exception ex) { Console.WriteLine("exception in NSpeexVoiceClass ->stop"); Console.WriteLine(ex.ToString()); } } public delegate void newData4Send(byte[] data, int dataLen); public event newData4Send OnNewDataRecv; public void DataArrived(byte[] data) { BinaryReader reader = new BinaryReader(new MemoryStream(data)); //while (reader.PeekChar() != -1) while(reader.BaseStream.Length-reader.BaseStream.Position>4) { int frameLength = reader.ReadInt32(); //Console.WriteLine("frame len" + frameLength); byte[] frame = reader.ReadBytes(frameLength); waveProvider.Write(frame, 0, frameLength); } } private void waveIn_DataAvailable(object sender, WaveInEventArgs e) { int samplesPerFrame = encoder.FrameSize; byte[] buffer = e.Buffer; short[] frame = new short[samplesPerFrame]; byte[] encodedFrame = new byte[e.BytesRecorded]; int encodedBytesSample = 0; byte[] upstreamEncodedSample = new byte[e.BytesRecorded]; int frameIndex = 0; for (int index = 0; index < e.BytesRecorded; index += 2, frameIndex = ++frameIndex % samplesPerFrame) { frame[frameIndex] = BitConverter.ToInt16(buffer, index); if (frameIndex != samplesPerFrame - 1) continue; if (preProcessor.Process(frame)) { int encodedBytes = encoder.Encode(frame, encodedFrame); if (encodedBytes != 0) { Array.Copy(BitConverter.GetBytes(encodedBytes), 0, upstreamEncodedSample, encodedBytesSample, sizeof(int)); encodedBytesSample += 4; Array.Copy(encodedFrame, 0, upstreamEncodedSample, encodedBytesSample, encodedBytes); encodedBytesSample += encodedBytes; } } } if (frameIndex != 0) { while (frameIndex < samplesPerFrame) { // fill the last frame with 0s frame[frameIndex++] = 0; } int encodedBytes = encoder.Encode(frame, encodedFrame); if (encodedBytes != 0) { Array.Copy(BitConverter.GetBytes(encodedBytes), 0, upstreamEncodedSample, encodedBytesSample, sizeof(int)); encodedBytesSample += 4; Array.Copy(encodedFrame, 0, upstreamEncodedSample, encodedBytesSample, encodedBytes); encodedBytesSample += encodedBytes; } } if (encodedBytesSample != 0) { var upstreamFrame = new byte[encodedBytesSample]; Array.Copy(upstreamEncodedSample, upstreamFrame, encodedBytesSample); //SM.Debug("Publishing: " + encodedBytesSample + " bytes"); if (OnNewDataRecv != null) { OnNewDataRecv(upstreamFrame, encodedBytesSample); } } else { //Console.WriteLine("DTX"); } } private bool isRecording; public bool IsRecording { get { return isRecording; } set { if (value != isRecording) { isRecording = value; } } } private void waveIn_RecordingStopped(object sender, EventArgs e) { IsRecording = false; } private void Check(Object state) { // This method is executed by a thread pool thread //Console.WriteLine("len=" + waveProvider.Length); if (waveProvider.Length == 0) { if (waveOutisPlaying) { Console.WriteLine("done playing"); waveOutisPlaying = false; if (OnFilePlayingComplet != null) { OnFilePlayingComplet(); } } } else { //Console.WriteLine("starting to play"); waveOutisPlaying = true; } } public delegate void FilePlayingComplet(); public event FilePlayingComplet OnFilePlayingComplet; public delegate void StreamVolume(int volume); public event StreamVolume OnStreamVolume; } }