I am trying to record voice using NAudio in C# and I am stuck at two places:
1. A crash:
With a slightly modified form of code from THIS SO page, I am getting a NullReferenceException
. Here is the crash log:
************** 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)
and the code is:
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);
}
}
Most of the times, this happens when I start recording THIRD time. Any idea what could be causing this?
*2. Modifying rate and channels at runtime.*
In my actual code, I am resetting wave format using s_WaveIn.WaveFormat = new WaveFormat(new_rate, new_channels);
before calling StartRecording()
. I am not calling Dispose()
because that would require resetting the DataAvailable
callback, and for that, I would need another message loop. Is this approach correct or should I first call Dispose and then reinitialize s_WaveIn with new format?
Thank you.
It Seems that DataAvailable callback is getting called even when buffer is null.
I modified a function in WaveIn.cs
file and its working fine now. I am not sure if this is correct, but for now, this is working for me.
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);
}
}
}
}