269 lines
6.3 KiB
C#
269 lines
6.3 KiB
C#
|
using System;
|
||
|
using System.Threading;
|
||
|
using System.Runtime.InteropServices;
|
||
|
|
||
|
namespace SafeMobileLib
|
||
|
{
|
||
|
internal class WaveInHelper
|
||
|
{
|
||
|
public static void Try(int err)
|
||
|
{
|
||
|
if (err != WaveNative.MMSYSERR_NOERROR)
|
||
|
throw new Exception(err.ToString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public delegate void BufferDoneEventHandler(IntPtr data, int size);
|
||
|
|
||
|
internal class WaveInBuffer : IDisposable
|
||
|
{
|
||
|
public WaveInBuffer NextBuffer;
|
||
|
|
||
|
private AutoResetEvent m_RecordEvent = new AutoResetEvent(false);
|
||
|
private IntPtr m_WaveIn;
|
||
|
|
||
|
private WaveNative.WaveHdr m_Header;
|
||
|
private byte[] m_HeaderData;
|
||
|
private GCHandle m_HeaderHandle;
|
||
|
private GCHandle m_HeaderDataHandle;
|
||
|
|
||
|
private bool m_Recording;
|
||
|
|
||
|
internal static void WaveInProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
|
||
|
{
|
||
|
if (uMsg == WaveNative.MM_WIM_DATA)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
GCHandle h = (GCHandle)wavhdr.dwUser;
|
||
|
WaveInBuffer buf = (WaveInBuffer)h.Target;
|
||
|
buf.OnCompleted();
|
||
|
}
|
||
|
catch(Exception ee)
|
||
|
{
|
||
|
Utils.WriteLine(ee.ToString(), ConsoleColor.Red);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public WaveInBuffer(IntPtr waveInHandle, int size)
|
||
|
{
|
||
|
m_WaveIn = waveInHandle;
|
||
|
|
||
|
m_HeaderHandle = GCHandle.Alloc(m_Header, GCHandleType.Pinned);
|
||
|
m_Header.dwUser = (IntPtr)GCHandle.Alloc(this);
|
||
|
m_HeaderData = new byte[size];
|
||
|
m_HeaderDataHandle = GCHandle.Alloc(m_HeaderData, GCHandleType.Pinned);
|
||
|
m_Header.lpData = m_HeaderDataHandle.AddrOfPinnedObject();
|
||
|
m_Header.dwBufferLength = size;
|
||
|
WaveInHelper.Try(WaveNative.waveInPrepareHeader(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)));
|
||
|
}
|
||
|
~WaveInBuffer()
|
||
|
{
|
||
|
Dispose();
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
if (m_Header.lpData != IntPtr.Zero)
|
||
|
{
|
||
|
WaveNative.waveInUnprepareHeader(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header));
|
||
|
m_HeaderHandle.Free();
|
||
|
m_Header.lpData = IntPtr.Zero;
|
||
|
}
|
||
|
m_RecordEvent.Close();
|
||
|
if (m_HeaderDataHandle.IsAllocated)
|
||
|
m_HeaderDataHandle.Free();
|
||
|
GC.SuppressFinalize(this);
|
||
|
}
|
||
|
|
||
|
public int Size
|
||
|
{
|
||
|
get { return m_Header.dwBufferLength; }
|
||
|
}
|
||
|
|
||
|
public IntPtr Data
|
||
|
{
|
||
|
get { return m_Header.lpData; }
|
||
|
}
|
||
|
|
||
|
public bool Record()
|
||
|
{
|
||
|
lock(this)
|
||
|
{
|
||
|
m_RecordEvent.Reset();
|
||
|
m_Recording = WaveNative.waveInAddBuffer(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)) == WaveNative.MMSYSERR_NOERROR;
|
||
|
return m_Recording;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void WaitFor()
|
||
|
{
|
||
|
if (m_Recording)
|
||
|
m_Recording = m_RecordEvent.WaitOne();
|
||
|
else
|
||
|
Thread.Sleep(0);
|
||
|
}
|
||
|
|
||
|
public void WaitForLimit500()
|
||
|
{
|
||
|
if (m_Recording)
|
||
|
m_Recording = m_RecordEvent.WaitOne(500);
|
||
|
else
|
||
|
Thread.Sleep(0);
|
||
|
}
|
||
|
|
||
|
private void OnCompleted()
|
||
|
{
|
||
|
m_RecordEvent.Set();
|
||
|
m_Recording = false;
|
||
|
}
|
||
|
|
||
|
public void SetRecordingOFF()
|
||
|
{
|
||
|
m_Recording = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class WaveInRecorder : IDisposable
|
||
|
{
|
||
|
private IntPtr m_WaveIn;
|
||
|
private WaveInBuffer m_Buffers; // linked list
|
||
|
private WaveInBuffer m_CurrentBuffer;
|
||
|
private Thread m_Thread;
|
||
|
private BufferDoneEventHandler m_DoneProc;
|
||
|
private bool m_Finished;
|
||
|
|
||
|
private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveInProc);
|
||
|
|
||
|
public static int DeviceCount
|
||
|
{
|
||
|
get { return WaveNative.waveInGetNumDevs(); }
|
||
|
}
|
||
|
|
||
|
public WaveInRecorder(int device, WaveFormat format, int bufferSize, int bufferCount, BufferDoneEventHandler doneProc)
|
||
|
{
|
||
|
m_DoneProc = doneProc;
|
||
|
WaveInHelper.Try(WaveNative.waveInOpen(out m_WaveIn, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION));
|
||
|
AllocateBuffers(bufferSize, bufferCount);
|
||
|
for (int i = 0; i < bufferCount; i++)
|
||
|
{
|
||
|
SelectNextBuffer();
|
||
|
m_CurrentBuffer.Record();
|
||
|
}
|
||
|
WaveInHelper.Try(WaveNative.waveInStart(m_WaveIn));
|
||
|
m_Thread = new Thread(new ThreadStart(ThreadProc));
|
||
|
m_Thread.Start();
|
||
|
}
|
||
|
~WaveInRecorder()
|
||
|
{
|
||
|
Dispose();
|
||
|
}
|
||
|
public void Dispose()
|
||
|
{
|
||
|
if (m_Thread != null)
|
||
|
try
|
||
|
{
|
||
|
m_Finished = true;
|
||
|
Console.WriteLine("Dispose WaveIN STEP1");
|
||
|
if (m_WaveIn != IntPtr.Zero)
|
||
|
WaveNative.waveInReset(m_WaveIn);
|
||
|
Console.WriteLine("Dispose WaveIN STEP2");
|
||
|
WaitForAllBuffers();
|
||
|
Console.WriteLine("Dispose WaveIN STEP3");
|
||
|
m_Thread.Join(500);
|
||
|
Console.WriteLine("Dispose WaveIN STEP4");
|
||
|
m_DoneProc = null;
|
||
|
Console.WriteLine("Dispose WaveIN STEP5");
|
||
|
FreeBuffers();
|
||
|
Console.WriteLine("Dispose WaveIN STEP6");
|
||
|
if (m_WaveIn != IntPtr.Zero)
|
||
|
WaveNative.waveInClose(m_WaveIn);
|
||
|
Console.WriteLine("Dispose WaveIN STEP7");
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
m_Thread = null;
|
||
|
Console.WriteLine("Dispose WaveIN STEP8");
|
||
|
m_WaveIn = IntPtr.Zero;
|
||
|
Console.WriteLine("Dispose WaveIN STEP9");
|
||
|
}
|
||
|
GC.SuppressFinalize(this);
|
||
|
}
|
||
|
private void ThreadProc()
|
||
|
{
|
||
|
while (!m_Finished)
|
||
|
{
|
||
|
Advance();
|
||
|
if (m_DoneProc != null && !m_Finished)
|
||
|
m_DoneProc(m_CurrentBuffer.Data, m_CurrentBuffer.Size);
|
||
|
m_CurrentBuffer.Record();
|
||
|
Thread.Sleep(1);
|
||
|
}
|
||
|
}
|
||
|
private void AllocateBuffers(int bufferSize, int bufferCount)
|
||
|
{
|
||
|
FreeBuffers();
|
||
|
if (bufferCount > 0)
|
||
|
{
|
||
|
m_Buffers = new WaveInBuffer(m_WaveIn, bufferSize);
|
||
|
WaveInBuffer Prev = m_Buffers;
|
||
|
try
|
||
|
{
|
||
|
for (int i = 1; i < bufferCount; i++)
|
||
|
{
|
||
|
WaveInBuffer Buf = new WaveInBuffer(m_WaveIn, bufferSize);
|
||
|
Prev.NextBuffer = Buf;
|
||
|
Prev = Buf;
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Prev.NextBuffer = m_Buffers;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
private void FreeBuffers()
|
||
|
{
|
||
|
m_CurrentBuffer = null;
|
||
|
if (m_Buffers != null)
|
||
|
{
|
||
|
WaveInBuffer First = m_Buffers;
|
||
|
m_Buffers = null;
|
||
|
|
||
|
Int32 deadin20steps = 0;
|
||
|
WaveInBuffer Current = First;
|
||
|
do
|
||
|
{
|
||
|
deadin20steps++;
|
||
|
WaveInBuffer Next = Current.NextBuffer;
|
||
|
Current.Dispose();
|
||
|
Current = Next;
|
||
|
} while((Current != First)&& (deadin20steps < 20));
|
||
|
}
|
||
|
}
|
||
|
private void Advance()
|
||
|
{
|
||
|
SelectNextBuffer();
|
||
|
m_CurrentBuffer.WaitFor();
|
||
|
}
|
||
|
private void SelectNextBuffer()
|
||
|
{
|
||
|
m_CurrentBuffer = m_CurrentBuffer == null ? m_Buffers : m_CurrentBuffer.NextBuffer;
|
||
|
}
|
||
|
private void WaitForAllBuffers()
|
||
|
{
|
||
|
WaveInBuffer Buf = m_Buffers;
|
||
|
Int32 maxim20Buffer = 0;
|
||
|
while ((Buf.NextBuffer != m_Buffers)&&(maxim20Buffer<20))
|
||
|
{
|
||
|
maxim20Buffer++;
|
||
|
Console.WriteLine("Count of buffers:"+maxim20Buffer);
|
||
|
Buf.SetRecordingOFF();
|
||
|
Buf.WaitForLimit500();
|
||
|
Buf = Buf.NextBuffer;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|