我编写了一个WinMM库包装器库,它公开了WaveOut和WaveIn类,用于录制和播放原始音频流。
一切都很好,但是为了遵循操作系统规范如何处理完成的缓冲区,我添加了一个线程,它可以取消缓冲区并释放内存。我也完成了所有的同步,因此这些类是可靠且线程安全的。
然而,似乎有一个罕见的问题,我向WaveOut设备添加缓冲区并且操作系统返回成功代码,但如果设备在字之后立即重置,则操作系统不会将缓冲区标记为已完成并返回它适用于应用程序。
似乎它正在失去缓冲区。所以,问题是,我正在跟踪发送到设备的各个缓冲区的数量,并阻止将Close()函数加入到清理它们的线程中。
任何想法或已知错误?
PS:这似乎不会发生在Vista的四核中,但确实发生在XP pro的双核中。
EDIT1:我完全愿意公开完整的源代码,一旦我上传并在codeplex上获得许可,如果这对任何人都有帮助。
EDIT2:将库发布到CodePlex:http://winmm.codeplex.com/
以下是导致问题的原因:
public partial class MainView : Form
{
private WaveIn waveIn = new WaveIn(WaveIn.WaveInMapperDeviceId);
private WaveOut waveOut = new WaveOut(WaveOut.WaveOutMapperDeviceId);
public MainView()
{
InitializeComponent();
WaveFormat format = WaveFormat.Pcm44Khz16BitMono;
waveOut.Open(format);
waveIn.DataReady += new EventHandler<DataReadyEventArgs>(WaveIn_DataReady);
// Tweaking these values affects the internal buffering thread.
// Setting too small of a QueueSize with too small of a BufferSize
// will cause buffer underruns, which will sound like choppy audio.
waveIn.BufferQueueSize = 200;
waveIn.BufferSize = 64;
waveIn.Open(format);
waveIn.Start();
}
void WaveIn_DataReady(object sender, DataReadyEventArgs e)
{
if (waveOut != null)
{
lock (waveOut)
{
// We have to check for null after the lock,
// because waveOut may have been disposed
// inside another lock.
if (waveOut != null)
{
waveOut.Write(e.Data);
}
}
}
}
private void MainView_FormClosed(object sender, FormClosedEventArgs e)
{
if (waveIn != null)
{
lock (waveIn)
{
waveIn.Dispose();
waveIn = null;
}
}
if (waveOut != null)
{
lock (waveOut)
{
waveOut.Dispose();
waveOut = null;
}
}
}
}
答案 0 :(得分:1)
我首先要创建一个单独的object
来锁定。这应该简化了很多空检查逻辑(大约一半,因为你在锁之前和之后检查)。
其次,Dispose
不会将您的变量设置为null
,因此您的其他检查仍将通过,因为该对象不为空,仅处置。所以我会这样做
waveOut.Dispose();
waveout = null;
确保它明确地设置为null。