在 C# 中处理更改的音频设备事件

发布于 2024-11-10 09:50:40 字数 199 浏览 1 评论 0原文

我想知道当我将耳机或其他输出设备插入(或拔出)声卡插孔时如何处理该事件。

在这里和谷歌上搜索为我提供了有关“naudio”库的信息,但它的文档非常差,而且该项目的协调员之一告诉我,他甚至不确定在他们的库中是否有可能。

我的最终目的是自动控制不同设备的音量,例如,当耳机处于活动状态时 - 设置 10% 音量,当扬声器处于活动状态时 - 设置 100%。

I'm wondering how to process the event when I insert (or extract) my headphones or another output device to soundcard jack.

Searching here and on google gives me information about "naudio" library, but it has very poor documentation to examine and also one of coordinators of this project told me he isn't sure than it even possible in their library.

My eventual purpose is automatic controlling volume for different devices, e.g. when headphones are active - set 10% volume, and when speakers are active - set 100%.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

七堇年 2024-11-17 09:50:41

您可以使用 NAudio 的 MMDeviceEnumerator 和 IMMNotificationClient 来完成此操作。但是,您可以添加 RegisterEndpointNotificationCallback 的实现 & UnRegisterEndpointNotificationCallback 到 MMDeviceEnumerator 类

实现是

 /// <summary>
       /// Registers a call back for Device Events
       /// </summary>
        /// <param name="client">Object implementing IMMNotificationClient type casted as IMMNotificationClient interface</param>
       /// <returns></returns>
        public int RegisterEndpointNotificationCallback([In] [MarshalAs(UnmanagedType.Interface)] IMMNotificationClient client)
        {
            //DeviceEnum declared below
            return deviceEnum.RegisterEndpointNotificationCallback(client);
        }

        /// <summary>
        /// UnRegisters a call back for Device Events
        /// </summary>
        /// <param name="client">Object implementing IMMNotificationClient type casted as IMMNotificationClient interface </param>
        /// <returns></returns>
        public int UnRegisterEndpointNotificationCallback([In] [MarshalAs(UnmanagedType.Interface)] IMMNotificationClient client)
        {
            //DeviceEnum declared below
            return deviceEnum.UnregisterEndpointNotificationCallback(client);
        } 

然后创建一个实现 IMMNotificationClient

示例的类:

class NotificationClientImplementation : NAudio.CoreAudioApi.Interfaces.IMMNotificationClient
    {

        public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
        {
            //Do some Work
            Console.WriteLine("OnDefaultDeviceChanged --> {0}", dataFlow.ToString());
        }

        public void OnDeviceAdded(string deviceId)
        {
             //Do some Work
            Console.WriteLine("OnDeviceAdded -->");
        }

        public void OnDeviceRemoved(string deviceId)
        {

            Console.WriteLine("OnDeviceRemoved -->");
             //Do some Work
        }

        public void OnDeviceStateChanged(string deviceId, DeviceState newState)
        {
            Console.WriteLine("OnDeviceStateChanged\n Device Id -->{0} : Device State {1}", deviceId, newState);
             //Do some Work
        }

        public NotificationClientImplementation()
        {
            //_realEnumerator.RegisterEndpointNotificationCallback();
            if (System.Environment.OSVersion.Version.Major < 6)
            {
                throw new NotSupportedException("This functionality is only supported on Windows Vista or newer.");
            }
        }

        public void OnPropertyValueChanged(string deviceId, PropertyKey propertyKey)
        {
             //Do some Work
             //fmtid & pid are changed to formatId and propertyId in the latest version NAudio
            Console.WriteLine("OnPropertyValueChanged: formatId --> {0}  propertyId --> {1}", propertyKey.formatId.ToString(), propertyKey.propertyId.ToString());
        }

    }

然后您所要做的就是

  1. 声明以下 NAudio 对象和 IMMNotificationClient

示例的实现:

private NAudio.CoreAudioApi.MMDeviceEnumerator deviceEnum = new NAudio.CoreAudioApi.MMDeviceEnumerator();
private NotificationClientImplementation notificationClient;
private NAudio.CoreAudioApi.Interfaces.IMMNotificationClient notifyClient;
  1. 然后将 notificationClient 类型转换为 IMMNotificationClient 并将其作为参数传递给 MMDeviceEnumerator

示例:

notificationClient = new NotificationClientImplementation();
notifyClient = (NAudio.CoreAudioApi.Interfaces.IMMNotificationClient)notificationClient;
deviceEnum.RegisterEndpointNotificationCallback(notifyClient);

希望这对某些人有帮助。感谢 MSDN 论坛,特别是 Michael Taylor
http://msmvps.com/blogs/p3net 帮助我解决这个问题。

谢谢&干杯。

You can do it using NAudio's MMDeviceEnumerator and IMMNotificationClient. However you add Implementations for RegisterEndpointNotificationCallback & UnRegisterEndpointNotificationCallback to MMDeviceEnumerator Class

The implementations are

 /// <summary>
       /// Registers a call back for Device Events
       /// </summary>
        /// <param name="client">Object implementing IMMNotificationClient type casted as IMMNotificationClient interface</param>
       /// <returns></returns>
        public int RegisterEndpointNotificationCallback([In] [MarshalAs(UnmanagedType.Interface)] IMMNotificationClient client)
        {
            //DeviceEnum declared below
            return deviceEnum.RegisterEndpointNotificationCallback(client);
        }

        /// <summary>
        /// UnRegisters a call back for Device Events
        /// </summary>
        /// <param name="client">Object implementing IMMNotificationClient type casted as IMMNotificationClient interface </param>
        /// <returns></returns>
        public int UnRegisterEndpointNotificationCallback([In] [MarshalAs(UnmanagedType.Interface)] IMMNotificationClient client)
        {
            //DeviceEnum declared below
            return deviceEnum.UnregisterEndpointNotificationCallback(client);
        } 

Then create a class that implements IMMNotificationClient

sample:

class NotificationClientImplementation : NAudio.CoreAudioApi.Interfaces.IMMNotificationClient
    {

        public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
        {
            //Do some Work
            Console.WriteLine("OnDefaultDeviceChanged --> {0}", dataFlow.ToString());
        }

        public void OnDeviceAdded(string deviceId)
        {
             //Do some Work
            Console.WriteLine("OnDeviceAdded -->");
        }

        public void OnDeviceRemoved(string deviceId)
        {

            Console.WriteLine("OnDeviceRemoved -->");
             //Do some Work
        }

        public void OnDeviceStateChanged(string deviceId, DeviceState newState)
        {
            Console.WriteLine("OnDeviceStateChanged\n Device Id -->{0} : Device State {1}", deviceId, newState);
             //Do some Work
        }

        public NotificationClientImplementation()
        {
            //_realEnumerator.RegisterEndpointNotificationCallback();
            if (System.Environment.OSVersion.Version.Major < 6)
            {
                throw new NotSupportedException("This functionality is only supported on Windows Vista or newer.");
            }
        }

        public void OnPropertyValueChanged(string deviceId, PropertyKey propertyKey)
        {
             //Do some Work
             //fmtid & pid are changed to formatId and propertyId in the latest version NAudio
            Console.WriteLine("OnPropertyValueChanged: formatId --> {0}  propertyId --> {1}", propertyKey.formatId.ToString(), propertyKey.propertyId.ToString());
        }

    }

Then all you have to do is

  1. Declare the following NAudio Objects and your implementation of IMMNotificationClient

Sample:

private NAudio.CoreAudioApi.MMDeviceEnumerator deviceEnum = new NAudio.CoreAudioApi.MMDeviceEnumerator();
private NotificationClientImplementation notificationClient;
private NAudio.CoreAudioApi.Interfaces.IMMNotificationClient notifyClient;
  1. Then type cast notificationClient as IMMNotificationClient and pass it as a parameter to MMDeviceEnumerator

Sample:

notificationClient = new NotificationClientImplementation();
notifyClient = (NAudio.CoreAudioApi.Interfaces.IMMNotificationClient)notificationClient;
deviceEnum.RegisterEndpointNotificationCallback(notifyClient);

Hope this helps some body. Thanks to MSDN Forums and particularly Michael Taylor
http://msmvps.com/blogs/p3net for helping me with this.

Thanks & Cheers.

度的依靠╰つ 2024-11-17 09:50:41

您将能够确定设备何时插入系统,您必须实施 IMMNotificationClient 通过 COM 互操作。基本上,您必须定义以下方法的实现:

请注意,在上述内容中,您最感兴趣的是:

  • OnDefaultDeviceChanged
  • OnDeviceAdded
  • OnDeviceStateChanged

但是,您应该注意底层硬件必须支持此功能,并且此功能仅在 Windows Vista 和 Windows Server 2008 上可用。

You will be able to determine when a device is plugged into the system, you will have to implement the IMMNotificationClient through COM interop. Basically, you will have to define the implementations of the following methods:

Note that of the above, the ones you are mostly interested in are:

  • OnDefaultDeviceChanged
  • OnDeviceAdded
  • OnDeviceStateChanged

However, you should be aware that the underlying hardware has to support this functionality, and that this is only available on Windows Vista and Windows Server 2008 on.

风铃鹿 2024-11-17 09:50:41

我修改了上面的 @randall-deetz 代码以使其自包含,您可以将其直接放入使用 NAudio 的任何应用程序中。感谢您提供了一个很棒的示例,它对我的​​项目确实有帮助!

internal class AudioDeviceChangeNotifier : NAudio.CoreAudioApi.Interfaces.IMMNotificationClient, IDisposable
{
    private NAudio.CoreAudioApi.MMDeviceEnumerator _deviceEnum = new NAudio.CoreAudioApi.MMDeviceEnumerator();

    public AudioDeviceChangeNotifier()
    {
        if (System.Environment.OSVersion.Version.Major < 6)
            throw new NotSupportedException("This functionality is only supported on Windows Vista or newer.");

        _deviceEnum.RegisterEndpointNotificationCallback(this);
    }

    public delegate void DefaultDeviceChangedHandler(DataFlow dataFlow, Role deviceRole, string defaultDeviceId);
    /// <summary>
    /// Raised when the default audio device is changed. 
    /// </summary>
    public event DefaultDeviceChangedHandler DefaultDeviceChanged;

    /// <summary>
    ///  Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when the default device changes. 
    /// </summary>
    /// <param name="dataFlow"></param>
    /// <param name="deviceRole"></param>
    /// <param name="defaultDeviceId"></param>
    public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
    {
        Debug.WriteLine($"AudioDeviceChangeNotifier::OnDefaultDeviceChanged - dataFlow: {dataFlow}, deviceRole: {deviceRole}, defaultDeviceId: {defaultDeviceId}");

        if (DefaultDeviceChanged != null)
            DefaultDeviceChanged(dataFlow, deviceRole, defaultDeviceId);
    }

    public delegate void DeviceAddedHandler(string deviceId);
    /// <summary>
    /// Raised when a new audio device is added.
    /// </summary>
    public event DeviceAddedHandler DeviceAdded;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device is added. 
    /// </summary>
    /// <param name="deviceId"></param>
    public void OnDeviceAdded(string deviceId)
    {
        Debug.WriteLine($"AudioDeviceChangeNotifier::OnDeviceAdded - deviceId: {deviceId}");

        if (DeviceAdded != null)
            DeviceAdded(deviceId);
    }

    public delegate void DeviceRemovedHandler(string deviceId);
    /// <summary>
    /// Raised when an audio device is removed.
    /// </summary>
    public event DeviceRemovedHandler DeviceRemoved;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device is removed. 
    /// </summary>
    /// <param name="deviceId"></param>
    public void OnDeviceRemoved(string deviceId)
    {
        Debug.WriteLine($"AudioDeviceChangeNotifier::OnDeviceRemoved - deviceId: {deviceId}");

        if (DeviceAdded != null)
            DeviceAdded(deviceId);
    }

    public delegate void DeviceStateChangedHandler(string deviceId, DeviceState newState);
    /// <summary>
    /// Raised when an audio device's state is changed.
    /// </summary>
    public event DeviceStateChangedHandler DeviceStateChanged;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device's state is changed. 
    /// </summary>
    /// <param name="deviceId"></param>
    /// <param name="newState"></param>
    public void OnDeviceStateChanged(string deviceId, DeviceState newState)
    {
        Debug.WriteLine($"AudioDeviceChangeNotifier::OnDeviceStateChanged - deviceId: {deviceId}, newState: {newState}");

        if (DeviceStateChanged != null)
            DeviceStateChanged(deviceId, newState);
    }
    
    public delegate void PropertyValueChangedHandler(string deviceId);
    /// <summary>
    /// Raised when a property value is changed.
    /// </summary>
    public event PropertyValueChangedHandler PropertyValueChanged;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device's property is changed. 
    /// </summary>
    /// <param name="deviceId"></param>
    /// <param name="propertyKey"></param>
    public void OnPropertyValueChanged(string deviceId, PropertyKey propertyKey)
    {
        Debug.WriteLine($"AudioDeviceChangeNotifier::OnPropertyValueChanged - deviceId: {deviceId}, propertyKey: {propertyKey}");

        if (PropertyValueChanged != null)
            PropertyValueChanged(deviceId);
    }

    public void Dispose()
    {
        _deviceEnum.UnregisterEndpointNotificationCallback(this);
    }
}

I modified @randall-deetz code above to make it self contained and you can drop this right into any application using NAudio. Thanks for a great sample, it really helped me with my project!

internal class AudioDeviceChangeNotifier : NAudio.CoreAudioApi.Interfaces.IMMNotificationClient, IDisposable
{
    private NAudio.CoreAudioApi.MMDeviceEnumerator _deviceEnum = new NAudio.CoreAudioApi.MMDeviceEnumerator();

    public AudioDeviceChangeNotifier()
    {
        if (System.Environment.OSVersion.Version.Major < 6)
            throw new NotSupportedException("This functionality is only supported on Windows Vista or newer.");

        _deviceEnum.RegisterEndpointNotificationCallback(this);
    }

    public delegate void DefaultDeviceChangedHandler(DataFlow dataFlow, Role deviceRole, string defaultDeviceId);
    /// <summary>
    /// Raised when the default audio device is changed. 
    /// </summary>
    public event DefaultDeviceChangedHandler DefaultDeviceChanged;

    /// <summary>
    ///  Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when the default device changes. 
    /// </summary>
    /// <param name="dataFlow"></param>
    /// <param name="deviceRole"></param>
    /// <param name="defaultDeviceId"></param>
    public void OnDefaultDeviceChanged(DataFlow dataFlow, Role deviceRole, string defaultDeviceId)
    {
        Debug.WriteLine(
quot;AudioDeviceChangeNotifier::OnDefaultDeviceChanged - dataFlow: {dataFlow}, deviceRole: {deviceRole}, defaultDeviceId: {defaultDeviceId}");

        if (DefaultDeviceChanged != null)
            DefaultDeviceChanged(dataFlow, deviceRole, defaultDeviceId);
    }

    public delegate void DeviceAddedHandler(string deviceId);
    /// <summary>
    /// Raised when a new audio device is added.
    /// </summary>
    public event DeviceAddedHandler DeviceAdded;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device is added. 
    /// </summary>
    /// <param name="deviceId"></param>
    public void OnDeviceAdded(string deviceId)
    {
        Debug.WriteLine(
quot;AudioDeviceChangeNotifier::OnDeviceAdded - deviceId: {deviceId}");

        if (DeviceAdded != null)
            DeviceAdded(deviceId);
    }

    public delegate void DeviceRemovedHandler(string deviceId);
    /// <summary>
    /// Raised when an audio device is removed.
    /// </summary>
    public event DeviceRemovedHandler DeviceRemoved;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device is removed. 
    /// </summary>
    /// <param name="deviceId"></param>
    public void OnDeviceRemoved(string deviceId)
    {
        Debug.WriteLine(
quot;AudioDeviceChangeNotifier::OnDeviceRemoved - deviceId: {deviceId}");

        if (DeviceAdded != null)
            DeviceAdded(deviceId);
    }

    public delegate void DeviceStateChangedHandler(string deviceId, DeviceState newState);
    /// <summary>
    /// Raised when an audio device's state is changed.
    /// </summary>
    public event DeviceStateChangedHandler DeviceStateChanged;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device's state is changed. 
    /// </summary>
    /// <param name="deviceId"></param>
    /// <param name="newState"></param>
    public void OnDeviceStateChanged(string deviceId, DeviceState newState)
    {
        Debug.WriteLine(
quot;AudioDeviceChangeNotifier::OnDeviceStateChanged - deviceId: {deviceId}, newState: {newState}");

        if (DeviceStateChanged != null)
            DeviceStateChanged(deviceId, newState);
    }
    
    public delegate void PropertyValueChangedHandler(string deviceId);
    /// <summary>
    /// Raised when a property value is changed.
    /// </summary>
    public event PropertyValueChangedHandler PropertyValueChanged;

    /// <summary>
    /// Triggered by NAudio.CoreAudioApi.MMDeviceEnumerator when an audio device's property is changed. 
    /// </summary>
    /// <param name="deviceId"></param>
    /// <param name="propertyKey"></param>
    public void OnPropertyValueChanged(string deviceId, PropertyKey propertyKey)
    {
        Debug.WriteLine(
quot;AudioDeviceChangeNotifier::OnPropertyValueChanged - deviceId: {deviceId}, propertyKey: {propertyKey}");

        if (PropertyValueChanged != null)
            PropertyValueChanged(deviceId);
    }

    public void Dispose()
    {
        _deviceEnum.UnregisterEndpointNotificationCallback(this);
    }
}
场罚期间 2024-11-17 09:50:41

我非常确定插入/拔出耳机或声卡中的其他任何东西不会生成任何系统事件

I was pretty sure that plugging/unplugging headphones or anything else in audiocard doesn't generate any system event whatsoever

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文