morphx666 / CoreAudio

Windows CoreAudio wrapper for .NET
https://whenimbored.xfx.net/2011/01/core-audio-for-net/
MIT License
95 stars 20 forks source link

[BUG] Exception on Enumerating NOTPRESENT devices #14

Closed Saya47 closed 2 years ago

Saya47 commented 2 years ago

Enumerating Active, Disabled and Unplugged devices work just fine but enumerating Not present devices produces this exception (which means also DEVICE_STATEMASK_ALL will cause this exception) :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CoreAudio;
using static System.Console;

namespace MyTests
{
    class Program
    {
        static void Main(string[] args)
        {
            MMDeviceEnumerator DevEnum = new MMDeviceEnumerator();
            {
                MMDeviceCollection Devices = DevEnum.EnumerateAudioEndPoints(EDataFlow.eAll, DEVICE_STATE.DEVICE_STATE_NOTPRESENT);
                List<MMDevice> DevicesList = Devices.ToList();
                foreach (MMDevice Item in DevicesList)
                WriteLine(Item.DeviceFriendlyName);
                ReadLine();
            }
        }
    }
}

Exception trace: image

System.Runtime.InteropServices.COMException: 'Exception from HRESULT: 0xE000020B'

Exception details:

System.Runtime.InteropServices.COMException
  HResult=0xE000020B
  Message=Exception from HRESULT: 0xE000020B
  Source=mscorlib
  StackTrace:
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at CoreAudio.PropertyStore.get_Item(PROPERTYKEY testKey)
   at CoreAudio.MMDevice.get_DeviceFriendlyName()
   at MyTests.Program.Main(String[] args) in A:\source\repos\ClassLibrary1-.NET_Framework\Class1.cs:line 21
Saya47 commented 2 years ago

I figured out the error! I think Not Present devices do not have a friendly name thus the exception rises, this was a bit hard for me as a beginner but hopefully this helps someone else! I needed a list of all devices (active, disabled and unplugged) with their names, which means I needed to edit the source code and modify DEVICE_STATE, so the NuGet package does not allow me to do that, so I added the CoreAudio as a submodule: git submodule add https://github.com/morphx666/CoreAudio and I deleted these folders: CoreAudio/Samples, CoreAudio/CoreAudio/obj so that it doesn't error for duplicate assemblies and deleted the CoreAudio.sln so that Visual Studio does not force load the CoreAudio solution instead of my projects solution and lastly added <LangVersion>8.0</LangVersion> to the <PropertyGroup> in my .csproj file. And now I can finally edit the source code:

DEVICE_STATE.cs

namespace CoreAudio
{
    [Flags]
    public enum DEVICE_STATE : uint
    {
        DEVICE_STATE_ACTIVE      = 0x00000001,
        DEVICE_STATE_DISABLED    = 0x00000002,
        DEVICE_STATE_NOTPRESENT  = 0x00000004,
        DEVICE_STATE_UNPLUGGED   = 0x00000008,
        DEVICE_STATEMASK_ALL     = 0x0000000F,
        DEVICE_STATEMASK_ACTIVE_DISABLED_UNPLUGGED = 0x0000000B
    }
}

Now I can use this to enumerate all Active, Disabled and Unplugged devices with this code:

using CoreAudio;
using System;
using System.Collections.Generic;
using static System.Console;

namespace MyTests
{
    class Program
    {
        static void Main(string[] args)
        {
            MMDeviceEnumerator DevEnum = new MMDeviceEnumerator();
            {
                MMDeviceCollection Devices = DevEnum.EnumerateAudioEndPoints(EDataFlow.eAll, DEVICE_STATE.DEVICE_STATEMASK_ACTIVE_DISABLED_UNPLUGGED);
                IEnumerator<MMDevice> DevicesList = Devices.GetEnumerator();
                int index = 0;
                while (DevicesList.MoveNext())
                {
                    index++;
                    WriteLine("index = {0} : {1}", index, DevicesList.Current.DeviceFriendlyName);
                }
                ReadLine();
            }
        }
    }
}