www.pudn.com > SoundDone.rar > WaveIn.cs
using System;
using System.Threading;
using System.Runtime.InteropServices;
namespace WaveLib
{
///
/// 音频输入帮助
///
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);
///
/// 代表将 WAVE 数据输入缓冲区的类
///
internal class WaveInBuffer : IDisposable
{
///
/// 缓冲池中的缓冲区
///
public WaveInBuffer NextBuffer;
///
/// 控制录制状态
///
private AutoResetEvent m_RecordEvent = new AutoResetEvent(false);
///
/// 波形输入设备句柄
///
private IntPtr m_WaveIn;
private WaveNative.WaveHdr m_Header;
///
/// 暂存 WAVE 文件的数据
///
private byte[] m_HeaderData;
///
/// 保存 WAVE 文件句柄,用于操作 WAVE 文件(因为是非托管对象)
///
private GCHandle m_HeaderHandle;
///
/// 保存 WAVE 文件数据句柄,用于操作 WAVE 文件数据(因为是非托管对象)
///
private GCHandle m_HeaderDataHandle;
///
/// 该缓冲区的当前录制状态
///
private bool m_Recording;
///
/// WAVE 数据输入满或停止时处理事件???
///
///
///
///
///
///
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
{
//throw new Exception() ;?
}
}
}
///
/// 构造函数
///
/// 波形输入设备句柄
/// 缓冲区大小
public WaveInBuffer(IntPtr waveInHandle, int size)
{
//保存波形输入设备句柄
m_WaveIn = waveInHandle;
//获得 WAVE 文件句柄
m_HeaderHandle = GCHandle.Alloc(m_Header, GCHandleType.Pinned);
//将本实例指定为用户数据区
m_Header.dwUser = (IntPtr)GCHandle.Alloc(this);
//为用户数据设置缓冲区
m_HeaderData = new byte[size];
//获得 WAVE 文件数据区句柄
m_HeaderDataHandle = GCHandle.Alloc(m_HeaderData, GCHandleType.Pinned);
//获得数据区的指针
m_Header.lpData = m_HeaderDataHandle.AddrOfPinnedObject();
//设置 WAVE 文件结构--缓冲区大小
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; }
}
///
/// 获得 WAVE 文件数据区句柄
///
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);
}
///
/// 确定当前录制已完成
///
private void OnCompleted()
{
m_RecordEvent.Set();
m_Recording = false;
}
}
///
/// 该类实现音频的录制
///
public class WaveInRecorder : IDisposable
{
///
/// 代表录制设备的名柄
///
private IntPtr m_WaveIn;
///
/// linked list
/// 保存该次录制所用的缓冲池
///
private WaveInBuffer m_Buffers;
///
/// 当前缓冲区
///
private WaveInBuffer m_CurrentBuffer;
///
/// 自定义的线程,用于起用录制线程
///
private Thread m_Thread;
///
/// 保存缓冲区满时的处理器
///
private BufferDoneEventHandler m_DoneProc;
///
/// 是否完成
///
private bool m_Finished;
///
/// 当前缓冲区个数
///
private int bufCount= 0 ;
///
/// 当前缓冲区大小
///
private int bufSize= 0 ;
///
/// ?
///
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)
{
this.bufCount= bufferCount ;
this.bufSize= bufferSize ;
//取得缓冲区满时事件
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;
if (m_WaveIn != IntPtr.Zero)
WaveNative.waveInReset(m_WaveIn);
WaitForAllBuffers();
m_Thread.Join();
m_DoneProc = null;
FreeBuffers();
if (m_WaveIn != IntPtr.Zero)
WaveNative.waveInClose(m_WaveIn);
}
finally
{
m_Thread = null;
m_WaveIn = IntPtr.Zero;
}
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();
}
}
///
/// 分配缓冲区
///
/// 缓冲区大小
/// 缓冲区数量
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;
WaveInBuffer Current = First;
do
{
WaveInBuffer Next = Current.NextBuffer;
Current.Dispose();
Current = Next;
} while(Current != First);
}
}
///
/// 将当前缓冲区移动到缓冲池中的下一个缓冲区
///
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;
while (Buf.NextBuffer != m_Buffers)
{
Buf.WaitFor();
Buf = Buf.NextBuffer;
}
}
}
}