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

问题描述 投票:0回答:4

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

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

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

c# .net events audio device
4个回答
19
投票

您可以使用 NAudio 的 MMDeviceEnumerator 和 IMMNotificationClient 来完成此操作。但是,您将 RegisterEndpointNotificationCallbackUnRegisterEndpointNotificationCallback 的实现添加到 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帮助我解决这个问题。

谢谢与干杯。


4
投票

您将能够确定设备何时插入系统,您必须通过 COM 互操作来实现

IMMNotificationClient
。基本上,您必须定义以下方法的实现:

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

  • OnDefaultDeviceChanged
  • OnDeviceAdded
  • OnDeviceStateChanged

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


0
投票

我修改了上面的 @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);
    }
}

-2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.