220 lines
7.6 KiB
C#
220 lines
7.6 KiB
C#
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<VolumeUpdatedEventArgs>(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;
|
|
}
|
|
}
|