Skip to content

Frequent switching of input devices cause StartRecording function deadlock. #1203

Open
@MooWeii

Description

Thanks to the author for the project. I'm using USB device. When I rapidly and frequently plug and unplug USB devices, it often leads to a deadlock when the program runs to the StartRecording function of WaveInEvent, causing the WPF desktop application to become unresponsive. Below is the code snippet:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    AudioDeviceChangeNotifier audioDeviceChangeNotifier;

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        audioDeviceChangeNotifier = new AudioDeviceChangeNotifier();
        audioDeviceChangeNotifier.DefaultDeviceChanged += AudioDeviceChangeNotifier_DefaultDeviceChanged;
        
        Thread thTime = new Thread(new ThreadStart(GetTime));
        thTime.IsBackground = true;
        thTime.Start();

        StartWaveRecord();
    }

    private void AudioDeviceChangeNotifier_DefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
    {
        if (GetCurrentMicVolume() != MicStatus.OK)
        {
            return;
        }

        StartWaveRecord();
    }

    WaveInProvider waveIn = null;
    private WaveInEvent waveSource = null;
    public static int wave_buffer_milliseconds = 600;
    public static int wave_buffer_collectbits = 16;
    public static int wave_buffer_collectchannels = 1;
    public static int wave_buffer_collectfrequency = 16000;
    private bool StartWaveRecord()
    {
        try
        {
            if (waveSource == null)
            {
                waveSource = new WaveInEvent();
                waveSource.BufferMilliseconds = wave_buffer_milliseconds;
                waveSource.WaveFormat = new WaveFormat(wave_buffer_collectfrequency, wave_buffer_collectbits, wave_buffer_collectchannels); 
                waveIn = new WaveInProvider(waveSource);
                waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(WaveIn);
                waveSource.RecordingStopped += WaveSource_RecordingStopped;
                waveSource.StartRecording();
            }
            else
            {
                waveSource.StartRecording();
            }
            return true;
        }
        catch (Exception e)
        {
            return false;
        }
    }

    private void WaveSource_RecordingStopped(object sender, StoppedEventArgs e)
    {
        try
        {
            if (e.Exception != null)
            {
                waveSource.Dispose();
                waveSource = null;
            }
        }
        catch { }
    }

    private void WaveIn(object sender, WaveInEventArgs e)
    {
        if (e.Buffer != null && e.BytesRecorded > 0)
        {
            try
            {
                waveIn.Read(e.Buffer, 0, e.BytesRecorded);
            }
            catch { }
        }
    }

    private MicStatus GetCurrentMicVolume()
    {
        ...
    }

    private void GetTime()
    {
        while (true)
        {
            Thread.Sleep(10);
            Now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");

            App.Current.Dispatcher.Invoke(() =>
            {
                Button_Click(null, null);
            });
        }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var a = SqliteHelper.ExecuteDataset("SELECT * FROM Formula");
    }

    private void OnPropertyChanged([CallerMemberName] string prop = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
    }

    private string now;

    public string Now
    {
        get { return now; }
        set { now = value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler? PropertyChanged;
}

public enum MicStatus
{
    OK,
    Mute,
    ZeroOutput,
    NotFound
}

I don't know if there's a problem with the way I use it. I've tried a lot of methods, and problems always come up.
Here is my complete project. Thank you for helping me.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions