C#动态更新pc音频的输入输出设备
1:这次我们要实现这样的一个功能,例如win11上音频输入输出列表,如下图所示
我们获取win上的音频输入输出设备的第三方为NAudio
以下代码为获取设备列表的实例:
public async Task UpdateDeviceListAsync()
{
await Task.Run(() =>
{
// 执行耗时的操作,例如从数据库读取数据、调用 Web API、执行复杂的计算等
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
MMDeviceCollection devices = enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active);
DeviceList = new List<string>(devices.Select(device => device.FriendlyName));
deviceComboBox.ItemsSource = DeviceList;
});
});
}
enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active);
DataFlow.All,会获取所有的输出输出设备。当然还有其他的两个参数,一个为
DataFlow.Render,DataFlow.Capture,指定他们就可以实现分别获取音频输入和输出设备了。如下图所示:
这个时候当我们点击下面的按钮时,就可以更新我们此刻电脑新的硬件设备了。当我们进行一个耳机的拔插动作时,我们只有点击下面的按钮时,方可以进行一个
设备列表的更新,但在实际应用中,用户可不会去点击这个按钮,特别是进行一个外设的拔插时,这个时候就需要我们动态的去更新这个设备列表。我们应该怎样做呢。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using VisioForge.Libs.NAudio.CoreAudioApi;
using System.Windows.Forms;
using System.ComponentModel;
using VisioForge.Libs.NAudio.CoreAudioApi.Interfaces;
using System.Collections.ObjectModel;
namespace TestWpf
{
/// <summary>
/// TableWindow.xaml 的交互逻辑
/// </summary>
public partial class TableWindow : Window, INotifyPropertyChanged
{
private MMDeviceEnumerator enumerator;
private DeviceNotificationCallback callback;
public static List<string>? DeviceList { get; set; }
public event PropertyChangedEventHandler? PropertyChanged;
public TableWindow()
{
InitializeComponent();
DataContext = this;
// 创建 MMDeviceEnumerator 实例
enumerator = new MMDeviceEnumerator();
UpdateDeviceListAsync();
// 创建 DeviceNotificationCallback 实例并注册为设备通知回调
callback = new DeviceNotificationCallback(this);
enumerator.RegisterEndpointNotificationCallback(callback);
}
public async Task UpdateDeviceListAsync()
{
await Task.Run(() =>
{
// 执行耗时的操作,例如从数据库读取数据、调用 Web API、执行复杂的计算等
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
MMDeviceCollection devices = enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active);
DeviceList = new List<string>(devices.Select(device => device.FriendlyName));
deviceComboBox.ItemsSource = DeviceList;
});
});
}
private void UpdateDeviceListButton_Click(object sender, RoutedEventArgs e)
{
UpdateDeviceListAsync();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.MessageBox.Show("11");
}
protected override void OnClosing(CancelEventArgs e)
{
System.Windows.MessageBox.Show("22");
}
}
class DeviceNotificationCallback : IMMNotificationClient
{
private TableWindow tableWindow;
public DeviceNotificationCallback(TableWindow window)
{
tableWindow = window;
}
public void OnDefaultDeviceChanged(DataFlow flow, Role role, string defaultDeviceId)
{
//tableWindow.UpdateDeviceList();
}
public void OnDeviceAdded(string pwstrDeviceId)
{
// tableWindow.UpdateDeviceList();
}
public void OnDeviceRemoved(string deviceId)
{
//tableWindow.UpdateDeviceList();
}
public void OnDeviceStateChanged(string deviceId, DeviceState newState)
{
tableWindow.UpdateDeviceListAsync();
}
public void OnPropertyValueChanged(string pwstrDeviceId, PropertyKey key)
{
//tableWindow.UpdateDeviceList();
}
// ...
}
}
这个是全部代码了,我们声明了一个类,实现了IMMNotificationClient接口,并在页面初始化的时候进行一个回调,并注册。
这个时候,当我们外设进行插拔的时候,我们程序就会进入回调函数里面,及时的在UI上更新这个设备列表,这样,我们在ui上就可以
动态的看到当用户插拔操作,以便于我们进行下面的逻辑实现。