Reputation: 1421
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.
Upvotes: 1
Views: 1627
Reputation: 174289
Your Main
method looks odd. What is the thread for?
Just use this:
[STAThread]
static void Main(string[] args)
{
init();
Application.Run();
}
Your init
method also runs the application. Why?
Try changing it to:
public static void init()
{
DeviceInit(44100, 2);
Thread t1 = new Thread(delegate() {
record();
});
t1.Start();
}
return;
is not needed at the end of a method returning void
.
Upvotes: 1
Reputation: 3
I got the same NullReferenceException. The author did not add lines to the proposed class WaveIn. Such use is not provided, as I understand it. Author library in the examples does not calls StopRecording (), and just stops to record incoming information, but continues to process it (for example to measure the volume), and calls StopRecording () for a complete stop to recive data to the data WaveIn. Thus, I believe that it is necessary to use a new WaveIn after calling StopRecording ().
Upvotes: 0
Reputation: 1
I think, it has to be done in this way:
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);
}
}
Upvotes: 0
Reputation: 1421
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);
}
}
}
}
Upvotes: 1