C# 将主音频音量的更改确定为事件(音量更改侦听器)
我想将windows的主音量绑定到程序中的滑块上。因此,我搜索并找到了一些方法来C# 将主音频音量的更改确定为事件(音量更改侦听器),c#,wpf,audio,C#,Wpf,Audio,我想将windows的主音量绑定到程序中的滑块上。因此,我搜索并找到了一些方法来获取或设置主卷+一些类似的库: 在某些情况下,我会看到一个带有循环的代码来获取体积值: 有些地方我看到了一个带有定时器的代码来获取音量值 我还看到了一些用于确定音量的示例,但在测试其中一个示例后,我在Windows 8的运行时看到了一些错误: 编辑: 现在我有下面的课程。我创建了它的一个实例,并使用propertchange事件通过Trace.WriteLine显示卷。但是,当我更改windows卷时,它
获取
或设置
主卷+一些类似的库:
- 在某些情况下,我会看到一个带有循环的代码来获取体积值:
- 有些地方我看到了一个带有定时器的代码来获取音量值
- 我还看到了一些用于确定音量的示例,但在测试其中一个示例后,我在Windows 8的运行时看到了一些错误:
编辑: 现在我有下面的课程。我创建了它的一个实例,并使用propertchange事件通过Trace.WriteLine显示卷。但是,当我更改windows卷时,它会导致未处理的错误
public class AudioEndpointVolumeEnforcer : INotifyPropertyChanged
{
private MMDeviceEnumerator mmDeviceEnumerator;
private MMDevice mmDevice;
private AudioEndpointVolume audioEndpointVolume;
private bool _deviceIsMuted;
private int _desiredVolume;
private int _volumePercent;
public AudioEndpointVolumeEnforcer()
{
try
{
mmDeviceEnumerator = new MMDeviceEnumerator();
mmDevice = mmDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
audioEndpointVolume = mmDevice.AudioEndpointVolume;
audioEndpointVolume.OnVolumeNotification += data =>
{
VolumePercent = Convert.ToInt16(data.MasterVolume*100);
_deviceIsMuted = data.Muted;
};
DesiredVolume = 65;
}
catch (Exception ex)
{
// Logging logic here
}
}
public int DesiredVolume
{
get { return _desiredVolume; }
private set
{
if (_desiredVolume == value) return;
_desiredVolume = value;
//NotifyOfPropertyChange();
OnPropertyChanged("DesiredVolume");
Enforce(_desiredVolume);
}
}
public int VolumePercent
{
get { return _volumePercent; }
private set
{
if (_volumePercent == value) return;
_volumePercent = value;
if (_volumePercent != _desiredVolume)
{
_volumePercent = _desiredVolume;
Enforce(_volumePercent);
}
}
}
public void Enforce(int pct, bool mute = false)
{
var adjusted = Convert.ToInt16(audioEndpointVolume.MasterVolumeLevelScalar*100);
if (adjusted != DesiredVolume)
{
audioEndpointVolume.MasterVolumeLevelScalar = pct/100f;
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
使用该类:
// Inside my window cunstractor >>
audioVolume = new AudioEndpointVolumeEnforcer();
audioVolume.PropertyChanged += MasterAudioVolumeChanged;
private void MasterAudioVolumeChanged(object obj, PropertyChangedEventArgs eventArgs)
{
Trace.WriteLine(eventArgs.PropertyName+" - "+audioVolume.DesiredVolume);
}
运行时错误:
输出面板显示访问冲突错误:
The program '[18488] Audio.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'
编辑 我通过断点和跟踪测试了上述代码。上述错误有时发生在以下部分:
audioEndpointVolume.OnVolumeNotification += data =>
{
VolumePercent = Convert.ToInt16(data.MasterVolume*100);
_deviceIsMuted = data.Muted;
};
例如,有时它发生在这一行:
_deviceIsMuted = data.Muted;
但是,当我通过F11进入下一步时,它不会显示程序内部的正常错误它会导致波纹管错误窗口和应用程序强制关闭
访问冲突
您的代码是否会更新控件以响应事件,例如轨迹栏或静音按钮?如果是这样,您可能需要使用线程安全的方法。控件只能由UI线程更新。需要检查是否是UI线程想要执行更新。如果不是,则返回True。Invoke然后使用委托来处理两个线程之间的通信。如果您不使用Me.Invoke,将出现访问冲突
Delegate Sub UpdateCallback(Volume As Integer, Muted As Boolean)
Public Overloads Sub Update(Volume As Integer, Muted As Boolean)
If tbVolume.InvokeRequired Then
Dim d As New UpdateCallback(AddressOf Update)
Me.Invoke(d, Volume, Muted)
Else
tbVolume.Value = Volume
_Mute = Muted
btnMuteUnmute.BackgroundImage = DirectCast(If(_Mute, _
My.Resources.mute, My.Resources.Unmute), Icon).ToBitmap
End If
End Sub
您的代码是否会更新控件以响应事件,例如轨迹栏或静音按钮?如果是这样,您可能需要使用线程安全的方法。控件只能由UI线程更新。需要检查是否是UI线程想要执行更新。如果不是,则返回True。Invoke然后使用委托来处理两个线程之间的通信。如果您不使用Me.Invoke,将出现访问冲突
Delegate Sub UpdateCallback(Volume As Integer, Muted As Boolean)
Public Overloads Sub Update(Volume As Integer, Muted As Boolean)
If tbVolume.InvokeRequired Then
Dim d As New UpdateCallback(AddressOf Update)
Me.Invoke(d, Volume, Muted)
Else
tbVolume.Value = Volume
_Mute = Muted
btnMuteUnmute.BackgroundImage = DirectCast(If(_Mute, _
My.Resources.mute, My.Resources.Unmute), Icon).ToBitmap
End If
End Sub
您可以这样使用NAudio库:
using NAudio;
using NAudio.CoreAudioApi;
private static MMDeviceEnumerator enumer = new MMDeviceEnumerator();
private MMDevice dev = enumer.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
public void Form1_Load(object sender, EventArgs e){
dev.AudioEndpointVolume.OnVolumeNotification += AudioEndpointVolume_OnVolumeNotification;
}
void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data)
{
// This shows data.MasterVolume, you can do whatever you want here
MessageBox.Show(data.MasterVolume.ToString());
}
本例使用WinForms项目,但也可以在其他地方创建事件
NAudio可以作为NuGet软件包安装,也可以从
音量范围从0.0f到1.0f,要获得0-100,只需执行以下操作:
(int)(data.MasterVolume * 100f)
您可以这样使用NAudio库:
using NAudio;
using NAudio.CoreAudioApi;
private static MMDeviceEnumerator enumer = new MMDeviceEnumerator();
private MMDevice dev = enumer.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
public void Form1_Load(object sender, EventArgs e){
dev.AudioEndpointVolume.OnVolumeNotification += AudioEndpointVolume_OnVolumeNotification;
}
void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data)
{
// This shows data.MasterVolume, you can do whatever you want here
MessageBox.Show(data.MasterVolume.ToString());
}
本例使用WinForms项目,但也可以在其他地方创建事件
NAudio可以作为NuGet软件包安装,也可以从
音量范围从0.0f到1.0f,要获得0-100,只需执行以下操作:
(int)(data.MasterVolume * 100f)
无论哪种方式看起来都有希望。你有没有试过?我想你已经回答了你自己的问题,因为你已经找到了这么多可能的解决方案。@kennyzx,我不知道有没有一种基于.NET中“事件”的安全方法,或者我必须通过“计时器”来实现它@kennyzx,我添加了我选择的方式的代码。您认为它的错误是什么?您应该在方法的第一行设置一个断点,并逐步找出导致访问冲突的原因。@dymanoid,我更新了我的问题,添加了一些关于通过断点跟踪程序的信息,然后。。。。!现在你怎么想?!无论哪种方式看起来都有希望。你有没有试过?我想你已经回答了你自己的问题,因为你已经找到了这么多可能的解决方案。@kennyzx,我不知道有没有一种基于.NET中“事件”的安全方法,或者我必须通过“计时器”来实现它@kennyzx,我添加了我选择的方式的代码。您认为它的错误是什么?您应该在方法的第一行设置一个断点,并逐步找出导致访问冲突的原因。@dymanoid,我更新了我的问题,添加了一些关于通过断点跟踪程序的信息,然后。。。。!现在你怎么想?!