我正在尝试使用C#中的NAudio录制语音,我被困在两个地方:
1. A crash:
使用THIS SO页面中稍微修改过的代码形式,我得到的是NullReferenceException
。这是崩溃日志:
************** Exception Text **************
System.NullReferenceException: Object reference not set to an instance of an object.
at NAudio.Wave.WaveIn.Callback(IntPtr waveInHandle, WaveMessage message, IntPtr userData, WaveHeader waveHeader, IntPtr reserved)
at NAudio.Wave.WaveWindow.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
,代码是:
using System;
using System.Windows.Forms;
using System.Threading;
using NAudio.Wave;
public class FOO
{
static WaveIn s_WaveIn;
[STAThread]
static void Main(string[] args)
{
init();
Application.Run();
}
public static void record()
{
while (true)
{
Console.WriteLine("Hit Enter to START Recording.\n");
Console.ReadLine();
s_WaveIn.StartRecording();
Console.WriteLine("Hit Enter to STOP recording.\n");
Console.ReadLine();
s_WaveIn.StopRecording();
}
}
public static void DeviceInit(int rate, int channels)
{
s_WaveIn = new WaveIn();
s_WaveIn.WaveFormat = new WaveFormat(rate, channels);
s_WaveIn.BufferMilliseconds = 1000;
s_WaveIn.DataAvailable += new EventHandler<WaveInEventArgs>(SendCaptureSamples);
}
public static void init()
{
DeviceInit(44100, 2);
Thread t1 = new Thread(delegate() {
record();
});
t1.Start();
}
static void SendCaptureSamples(object sender, WaveInEventArgs e)
{
Console.WriteLine("Bytes recorded: {0}", e.BytesRecorded);
}
}
大多数情况下,当我开始记录第三次时会发生这种情况。知道是什么原因引起的吗?
*2. Modifying rate and channels at runtime.*
在我的实际代码中,我在调用s_WaveIn.WaveFormat = new WaveFormat(new_rate, new_channels);
之前使用StartRecording()
重置波形格式。我没有调用Dispose()
,因为这需要重置DataAvailable
回调,为此,我需要另一个消息循环。这种方法是正确的还是应该首先调用Dispose,然后使用新格式重新初始化s_WaveIn?
谢谢。
答案 0 :(得分:1)
您的Main
方法看起来很奇怪。线程是什么?
请使用:
[STAThread]
static void Main(string[] args)
{
init();
Application.Run();
}
您的init
方法也会运行该应用程序。为什么呢?
尝试将其更改为:
public static void init()
{
DeviceInit(44100, 2);
Thread t1 = new Thread(delegate() {
record();
});
t1.Start();
}
返回return;
的方法结束时不需要 void
。
答案 1 :(得分:1)
看起来,即使缓冲区为空,也会调用DataAvailable回调。
我在WaveIn.cs
文件中修改了一个函数,现在工作正常。我不确定这是否正确,但就目前而言,这对我有用。
private void Callback(IntPtr waveInHandle, WaveInterop.WaveMessage message, IntPtr userData, WaveHeader waveHeader, IntPtr reserved)
{
if (message == WaveInterop.WaveMessage.WaveInData)
{
GCHandle hBuffer = (GCHandle)waveHeader.userData;
WaveInBuffer buffer = (WaveInBuffer)hBuffer.Target;
if (buffer != null)
{
if (DataAvailable != null)
{
DataAvailable(this, new WaveInEventArgs(buffer.Data, buffer.BytesRecorded));
}
if (recording)
{
buffer.Reuse();
}
}
else
{
if (RecordingStopped != null)
{
RecordingStopped(this, EventArgs.Empty);
}
}
}
}
答案 2 :(得分:0)
我认为,必须以这种方式完成:
GCHandle hBuffer = (GCHandle)waveHeader.userData;
WaveInBuffer buffer = (WaveInBuffer)hBuffer.Target;
if (buffer == null)
{
return; // with this new line, everything works fine
}
if (DataAvailable != null)
{
DataAvailable(this, new WaveInEventArgs(buffer.Data, buffer.BytesRecorded));
}
if (recording)
{
buffer.Reuse();
}
else
{
if (RecordingStopped != null)
{
RecordingStopped(this, EventArgs.Empty);
}
}
答案 3 :(得分:0)
我得到了相同的NullReferenceException。作者没有在建议的类 WaveIn 中添加行。 据我所知,没有提供这种用途。示例中的作者库不调用 StopRecording(),只是停止记录传入信息,但继续处理它(例如测量音量),并调用 StopRecording()< / strong>完全停止将数据恢复到数据 WaveIn 。 因此,我认为在调用 StopRecording()之后有必要使用新的WaveIn。