1

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);

        }
Community
  • 1
  • 1
Robert Koernke
  • 436
  • 3
  • 18
  • What exactly do you want to configure? Could you be more specific – EugeneK Jan 02 '17 at 03:10
  • I want to change a playback device from 2CH to 5.1. Or the Samplerate to 24bit,48000, from the default. I'm not sure NAudio, that I cited above has the tools. I've tried a couple of other APIs, with little documentation, or the capability just isn't there. – Robert Koernke Jan 03 '17 at 12:12

2 Answers2

1

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);
            }
        }
EugeneK
  • 2,164
  • 1
  • 16
  • 21
  • Your answer looks good. But when downloading their source. I get a million unresolvable errors. Like it comes with the wrong framework or missing dependencies. Specifically I get "invalid token ';'" on stuff like '=>' and 'identifier expected...'. 127 errors. – Robert Koernke Jan 11 '17 at 03:45
  • Which version did you use? I got latest from here https://github.com/naudio/NAudio and it compiles without errors in VS 2015 – EugeneK Jan 11 '17 at 05:56
  • Ok Ignore the comments above. I have built it in VS2015. The next issue is that it does not work. In Debug I see that it hits the setter with the correct values, but the playback device never changes from 2CH to 5.1. – Robert Koernke Jan 12 '17 at 04:11
  • Are you running it as administrator? – EugeneK Jan 12 '17 at 06:07
  • 1
    Also try different keys, you can use SysInternals ProcessMonitor to check which values are changed in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render when you manually change configuration – EugeneK Jan 12 '17 at 06:34
  • On my machine 9 values are updated in registry when configuration is changed, I'm not sure if they are driver dependent or not. So you can check what values are changed on your machine and then recreate this behaviour using API, or it maybe easier to just write directly to this registry key. (Also I made small update in the code above because it was writing value with incorrect datatype) – EugeneK Jan 12 '17 at 07:39
  • Yes it would blow up in non-administrator mode. I'll check out your findings. – Robert Koernke Jan 12 '17 at 12:04
  • Still does not work. Processmon brings up 5000 events when filtering for MMDevices. Not sure what I'm looking for. – Robert Koernke Jan 12 '17 at 13:20
  • 1
    To reduce number of events add filter to only show ProcessName = svchost.exe and Operation=RegSetValue – EugeneK Jan 12 '17 at 17:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/133039/discussion-between-robert-koernke-and-eugenek). – Robert Koernke Jan 12 '17 at 22:33
1

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.

Robert Koernke
  • 436
  • 3
  • 18