How to Change Speaker Configuration in Windows in C#?

1.8k Views Asked by At

I am aware of this old thread: What APIs exist?, but it really didn't answer the question. And it has been a number of years. Yes I am using the NAudio.CoreAudioApi But I'm not finding any useful information.

MMDevice.Properties is readonly. Is there a way to do this programmatically in C#? I'm no longer sure.

You can also find the channels with: AudioEndpointVolumeChannels, but it only allows Channels.count.

Another solution I thought of is with some sort of 'Macro' that changes with mouse-click movements, but that's pretty ugly.

That NAudio API, should have the right-stuff, but I'm not finding any documentation there-in on how to do it. I've googled for like an entire day and found nothing. The old CoreAPIs were moved in there.

using NAudio.Wave;
using NAudio.CoreAudioApi;

        //Can't do anything with these Devices, but change the volume????!!!
        var deviceEnum = new MMDeviceEnumerator();
        var devices = deviceEnum.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).ToList();
        foreach (MMDevice device in devices)
        {
            Console.WriteLine(device.FriendlyName);

        }
2

There are 2 best solutions below

0
On BEST ANSWER

The method that Eugene and I found that worked was to find the Playback devices Registry -- 'Render' That is: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Aud‌​io\Render Then forward slash {Guid}... Your playback device. Make sure your device is in 5.1 or greater mode.

Then 'Export' that to a file. When you need to restore to 5.1 or greater, which would also include the 'Sample Rate'. Then in code use the following from the exported file:

Process regeditProcess = Process.Start("regedit.exe", "/s playback.reg");
regeditProcess.WaitForExit();

Which will make sure the keys are properly restored. Its still not the best way I would like to see. But it certainly works.

10
On

Windows API supports modifying properties, but NAudio does not expose this ability for some reason. It is pretty easy to add this by modifying NAudio source.

in NAudio\CoreAudioApi\PropVariant.cs add

    /// <summary>
    /// Creates a new PropVariant containing a uint value
    /// </summary>
    public static PropVariant FromUInt(uint value)
    {
        return new PropVariant() { vt = (short)VarEnum.VT_UI4, ulVal = value };
    }

in NAudio\CoreAudioApi\PropertyStore.cs add following method

    /// <summary>
    /// Sets property value at specified key
    /// </summary>
    /// <param name="key">Index</param>
    /// <param name="value">Value</param>
    public void SetValue(PropertyKey key, PropVariant value)
    {
        Marshal.ThrowExceptionForHR(storeInterface.SetValue(ref key, ref value));
    }

in NAudio\CoreAudioApi\MMDevice.cs

modify following line

        Marshal.ThrowExceptionForHR(deviceInterface.OpenPropertyStore(StorageAccessMode.Read, out propstore));

to be

        Marshal.ThrowExceptionForHR(deviceInterface.OpenPropertyStore(StorageAccessMode.ReadWrite, out propstore));

now if you rebuild NAudio.dll with these changes your example may look like this to change playback device to be 5.1 (you have to run it as administrator or it will fail)

        var deviceEnum = new MMDeviceEnumerator();
        var devices = deviceEnum.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).ToList();
        foreach (MMDevice device in devices)
        {
            Console.WriteLine(device.FriendlyName);
            if (device.Properties.Contains(PropertyKeys.PKEY_AudioEndpoint_PhysicalSpeakers))
            {
                var value = device.Properties[PropertyKeys.PKEY_AudioEndpoint_PhysicalSpeakers];
                Console.WriteLine("Current value: " + value.Value.ToString());
                // set configuration to 5.1, value is taken from ksmedia.h from Windows Driver Kit
                PropVariant newvalue = PropVariant.FromUInt(63);
                device.Properties.SetValue(PropertyKeys.PKEY_AudioEndpoint_PhysicalSpeakers, newvalue);
            }
        }