Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling changed audio device event in c#

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%.

like image 574
Anton Sergeyev Avatar asked May 28 '11 17:05

Anton Sergeyev


2 Answers

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.

like image 127
Mohtashim Avatar answered Nov 13 '22 09:11

Mohtashim


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:

  • OnDefaultDeviceChanged
  • OnDeviceAdded
  • OnDeviceRemoved
  • OnDeviceStateChanged
  • OnPropertyValueChanged

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.

like image 4
casperOne Avatar answered Nov 13 '22 09:11

casperOne