C# 使用 Core Audio APIs 获取音频设备信息

  • Post author:
  • Post category:其他




1. 开头

最一开始写这个的目的是为了控制播放和输出设备的音量,开启静音等。但是,在使用C#调用Com的时候发现了一个神奇的事情。

// IMMDeviceEnumerator 为接口
IMMDeviceEnumerator mMDeviceEnumerator = new IMMDeviceEnumerator();

没错,可以实例化一个接口?神奇的操作😃。

所以,这篇的主要目的是写为什么可以实例化一个接口这么神奇的操作。接下来会写怎么操作音量,还有怎么选择默认设备😋

想看实现获取音频设备列表 代码的直接看 下面, 想看为什么能实例化一个接口的可以直接看最后。



2. 功能代码实现

Com接口的相关P/Invoke 封装看附录

 		static PROPERTYKEY PKEY_DeviceInterface_FriendlyName = new PROPERTYKEY() {
    fmtid = new Guid(0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22), pid = 2 };  //PKEY_DeviceInterface_FriendlyName
        static PROPERTYKEY PKEY_Device_FriendlyName = new PROPERTYKEY() {
    fmtid = new Guid(0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 14 }; //PKEY_Device_FriendlyName
		static void Main(string[] args)
        {
   

            IMMDeviceEnumerator mMDeviceEnumerator = new IMMDeviceEnumerator();
            IMMDeviceCollection deviceCollection;
            mMDeviceEnumerator.EnumAudioEndpoints(EDataFlow.eRender, DeviceState.All, out deviceCollection);

            uint count = 0;
            deviceCollection.GetCount(out count);
            Console.WriteLine(count);
            for (uint i = 0; i < count; i++)
            {
   
                deviceCollection.Item(i, out IMMDevice device);
                device.GetId(out string id);
                Console.WriteLine(id);

                device.GetState(out uint state);
                Console.WriteLine(state);

                device.OpenPropertyStore(StorageAccessMode.Read, out IPropertyStore property);


                PROPVARIANT pROPVARIANT = new PROPVARIANT();
                property.GetValue(ref PKEY_Device_FriendlyName, out pROPVARIANT);
                Console.WriteLine(pROPVARIANT.Value);

            }

        }



3 关于神奇操作的分析

最简单的一句话 就是

CoClass

这个attribute 使用这个之后 编译器会将

IMMDeviceEnumerator mMDeviceEnumerator = new IMMDeviceEnumerator();

理解为

IMMDeviceEnumerator mMDeviceEnumerator = (IMMDeviceEnumerator) Activator.CreateInstance(Type.GetTypeFromCLSID
        (new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")));

在这里插入图片描述

如果,这篇文章的理解有错误,欢迎指正。


相关解析可以参考:


How does the C# compiler detect COM types?




FAKING COM TO FOOL THE C# COMPILER



附录

相关P/Invoke封装

       #region Struct
        public struct WAVEFORMATEX
        {
   
            ushort wFormatTag;         /* format type */
            ushort nChannels;          /* number of channels (i.e. mono, stereo...) */
            uint nSamplesPerSec;     /* sample rate */
            uint nAvgBytesPerSec;    /* for buffer estimation */
            ushort nBlockAlign;        /* block size of data */
            ushort wBitsPerSample;     /* number of bits per sample of mono data */
            ushort cbSize;             /* the count in bytes of the size of */
            /* extra information (after cbSize) */
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct PROPERTYKEY
        {
   
            public Guid fmtid;
            public uint pid;
        }
        public struct BLOB
        {
   
            public uint cbSize;
            /* [size_is] */
            public IntPtr/* BYTE* */ pBlobData;
        }


        [StructLayout(LayoutKind.Explicit)]
        public struct PROPVARIANT
        {
   
            /// <summary>
            /// Value type tag.
            /// </summary>
            [FieldOffset(0)] public short vt;
            /// <summary>
            /// Reserved1.
            /// </summary>
            [FieldOffset(2)] public 



版权声明:本文为z971130192原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。