Search code examples
c#nullreferenceexceptionnaudio

NullReferenceException when recording with NAudio (in c#)


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.


Solution

  • 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);
        }
    }
    }
    

    }