VB.NET 6.0(Windows 11)中CoreAudio如何实现ControlChangeNotify回调?
VB.NET 6.0 实现 CoreAudioApi ControlChangeNotify 回调方案
我用VB.NET 6.0开发一款音量控制应用,引用CoreAudioApi.dll,已经实现了以下功能:
- 修改默认播放和捕获设备的音量
- 对默认设备执行静音操作
- 调整播放设备的声道平衡
- 列出所有设备的全名、GUID字符串及状态
但在设置ControlChangeNotify回调时遇到了瓶颈——这个功能在C语言里实现起来很简单,我查了大量资料还是没搞定。经过多次尝试和调整,最终通过以下步骤解决了问题:
- 在回调类中,为主窗体需要更新的每个控件类型声明公共事件
- 启动
BackgroundWorker,在回调类被调用后延迟10毫秒异步处理数据 - 从
pNotifyData指针解析计算出新的音频参数值 - 触发主窗体中滑块、复选框和标签对应的更新事件
- 在主窗体中添加对应的事件处理程序
- 为每种控件类型编写带委托的处理例程
完整实现代码
' 回调类实现 Imports CoreAudioApi Imports System.ComponentModel Public Class AudioControlNotify Implements IMMNotificationClient ' 声明对应控件的更新事件 Public Event VolumeChanged(ByVal newVolume As Single) Public Event MuteChanged(ByVal isMuted As Boolean) Public Event DeviceChanged(ByVal deviceId As String) Private bgWorker As New BackgroundWorker() Public Sub New() bgWorker.WorkerSupportsCancellation = True AddHandler bgWorker.DoWork, AddressOf BackgroundProcess End Sub ' IMMNotificationClient 接口实现 Public Sub OnDefaultDeviceChanged(dataFlow As EDataFlow, role As ERole, defaultDeviceId As String) Implements IMMNotificationClient.OnDefaultDeviceChanged bgWorker.RunWorkerAsync(New NotifyData With {.Type = NotifyType.DeviceChange, .DeviceId = defaultDeviceId}) End Sub Public Sub OnPropertyValueChanged(deviceId As String, key As PropertyKey) Implements IMMNotificationClient.OnPropertyValueChanged If key.fmtid = New Guid("5CDF2C82-841E-4546-9722-0CF74078229A") AndAlso key.pid = 1 Then ' 音量或静音属性变更 Dim device As New MMDevice(deviceId) bgWorker.RunWorkerAsync(New NotifyData With {.Type = NotifyType.VolumeChange, .Volume = device.AudioEndpointVolume.MasterVolumeLevelScalar, .IsMuted = device.AudioEndpointVolume.Mute}) device.Dispose() End If End Sub ' 其他接口方法空实现 Public Sub OnDeviceAdded(deviceId As String) Implements IMMNotificationClient.OnDeviceAdded End Sub Public Sub OnDeviceRemoved(deviceId As String) Implements IMMNotificationClient.OnDeviceRemoved End Sub Public Sub OnDeviceStateChanged(deviceId As String, newState As DEVICE_STATE) Implements IMMNotificationClient.OnDeviceStateChanged End Sub Public Sub OnSessionCreated(sessionId As String) Implements IMMNotificationClient.OnSessionCreated End Sub Public Sub OnSessionDisconnected(sessionId As String, disconnectReason As ESessionDisconnectReason) Implements IMMNotificationClient.OnSessionDisconnected End Sub Public Sub OnSessionEnded(sessionId As String, endReason As ESessionEndedReason) Implements IMMNotificationClient.OnSessionEnded End Sub Public Sub OnSessionVolumeChanged(sessionId As String, volume As Single, isMuted As Boolean) Implements IMMNotificationClient.OnSessionVolumeChanged End Sub Private Sub BackgroundProcess(sender As Object, e As DoWorkEventArgs) ' 延迟10毫秒确保数据稳定 System.Threading.Thread.Sleep(10) Dim notifyData As NotifyData = CType(e.Argument, NotifyData) Select Case notifyData.Type Case NotifyType.VolumeChange RaiseEvent VolumeChanged(notifyData.Volume) RaiseEvent MuteChanged(notifyData.IsMuted) Case NotifyType.DeviceChange RaiseEvent DeviceChanged(notifyData.DeviceId) End Select End Sub Private Enum NotifyType VolumeChange DeviceChange End Enum Private Class NotifyData Public Property Type As NotifyType Public Property Volume As Single Public Property IsMuted As Boolean Public Property DeviceId As String End Class End Class ' 主窗体代码示例 Public Class MainForm Private audioNotify As AudioControlNotify Private deviceEnumerator As New MMDeviceEnumerator() Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load audioNotify = New AudioControlNotify() ' 注册事件处理 AddHandler audioNotify.VolumeChanged, AddressOf UpdateVolumeSlider AddHandler audioNotify.MuteChanged, AddressOf UpdateMuteCheckbox AddHandler audioNotify.DeviceChanged, AddressOf UpdateDeviceList ' 注册通知客户端 deviceEnumerator.RegisterEndpointNotificationCallback(audioNotify) End Sub ' 音量滑块更新委托及处理 Private Delegate Sub UpdateVolumeDelegate(newVolume As Single) Private Sub UpdateVolumeSlider(newVolume As Single) If InvokeRequired Then Invoke(New UpdateVolumeDelegate(AddressOf UpdateVolumeSlider), newVolume) Else VolumeSlider.Value = CInt(newVolume * 100) VolumeLabel.Text = $"{CInt(newVolume * 100)}%" End If End Sub ' 静音复选框更新委托及处理 Private Delegate Sub UpdateMuteDelegate(isMuted As Boolean) Private Sub UpdateMuteCheckbox(isMuted As Boolean) If InvokeRequired Then Invoke(New UpdateMuteDelegate(AddressOf UpdateMuteCheckbox), isMuted) Else MuteCheckBox.Checked = isMuted End If End Sub ' 设备列表更新委托及处理 Private Delegate Sub UpdateDeviceDelegate(deviceId As String) Private Sub UpdateDeviceList(deviceId As String) If InvokeRequired Then Invoke(New UpdateDeviceDelegate(AddressOf UpdateDeviceList), deviceId) Else ' 重新加载设备列表逻辑 DeviceListBox.Items.Clear() For Each device As MMDevice In deviceEnumerator.EnumerateAudioEndPoints(EDataFlow.eRender, EDeviceState.DEVICE_STATE_ACTIVE) DeviceListBox.Items.Add($"{device.FriendlyName} - {device.ID}") Next End If End Sub Private Sub MainForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing deviceEnumerator.UnregisterEndpointNotificationCallback(audioNotify) audioNotify.Dispose() deviceEnumerator.Dispose() End Sub End Class
内容的提问来源于stack exchange,提问作者David Patterson
相关产品推荐
相关产品推荐

