Search code examples
c#audiodefaultendpointcscore

using an Audio Endpoint other than 'DefaultAudioEndpoint' in C#


This program is an audio visualizer for an rgb keyboard that listens to windows' default audio device. My audio setup is a bit more involved, and I use way more than just the default audio device. For instance, when I play music from Winamp it goes through the device Auxillary 1 (Synchronous Audio Router) instead of Desktop Input (Synchronous Audio Router) which I have set as Default. I'd like to be able change the device that the program listens to for the visualization.

I found in the source where the audio device is declared; Lines 32-36 in CSCoreAudioInput.cs:

public void Initialize()
{
    MMDevice captureDevice = MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console);
    WaveFormat deviceFormat = captureDevice.DeviceFormat;
    _audioEndpointVolume = AudioEndpointVolume.FromDevice(captureDevice);
}

The way that I understand it from the documentation, the section MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console) is where Windows gives the application my default IMMEndpoint "Desktop Input."

How would I go about changing DefaultAudioEndpoint?

Further Reading shows a few ways to get an IMMDevice, with DefaultAudioEnpoint being one of them. It seems to me that I'd have to enumerate the devices, and then separate out Auxillary 1 (Synchronous Audio Router) using PKEY_Device_FriendlyName. That's a bit much for me, as I have little to no C# experience. Is there an easier way to go about choosing a different endpoint? Am I on the right track? or am I missing the mark completely?

Also, what is the difference between MMDevice and IMMDevice? The source only seems to use MMDevice while all the Microsoft documentation references IMMDevice.

Thanks.


Solution

  • I DID IT!

    I've found why the program uses MMDevice rather than IMMDevice. The developer has chosen to use the CSCore Library rather than Windows' own Core Audio API.

    From continued reading of the CSCore MMDeviceEnumerator Documentation, it looks like I'll have to make a separate program that outputs all endpoints and their respective Endpoint ID Strings. Then I can substitute the DefaultAudioEndpoint method with the GetDevice(String id) method, where String id is the ID of whichever Endpoint I chose from the separate program.

    To find the the Endpoint I wanted, I wrote this short program to find all the info I wanted:

    static void Main(string[] args)
        {
            MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
            MMDeviceCollection collection = enumerator.EnumAudioEndpoints(DataFlow.Render,DeviceState.Active);
            Console.WriteLine($"\nNumber of active Devices: {collection.GetCount()}");
    
            int i = 0;
            foreach (MMDevice device in collection){
    
                Console.WriteLine($"\n{i} Friendly name: {device.FriendlyName}");
                Console.WriteLine($"Endpoint ID: {device.DeviceID}");
                i++;
            }
            Console.ReadKey();
        }
    

    This showed me that the Endpoint I wanted was item number 3 (2 in an array) on my list, and instead of using GetDevice(String id) I used ItemAt(int deviceIndex).

    MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
    MMDeviceCollection collection = enumerator.EnumAudioEndpoints(DataFlow.Render,DeviceState.Active);
    MMDevice captureDevice = collection.ItemAt(2);
    

    However in this case, the program was not using captureDevice to bring in the audio data. These were the magic lines:

    _capture = new WasapiLoopbackCapture(100, new WaveFormat(deviceFormat.SampleRate, deviceFormat.BitsPerSample, i));
    _capture.Initialize();
    

    I found that WasapiLoopbackCapture uses Windows' default device unless changed, and the code was using DefaultAudioEndpoint to get the properties of the default device. So I added

    _capture.Device = captureDevice;
    //before
    _capture.Initialize();
    

    And now the program properly pulls the audio data off of my non-default audio endpoint.