• C# 通过winmm枚举音频设备



    前言

    使用C#做音频录制时需要获取音频设备信息,比如使用ffmpeg进行录制需要先获取音频设备名称,再Windows上获取音频设备的方法有不少,其中比较简单的就是使用winmm,这是一套比较旧的api但是使用方法简单,当然有个缺陷就是音频名称不能超过32个字符,超过会被截断,当然如果作为winmm的采集或播放配套使用则不会有问题。


    一、如何实现?

    需要先导入winmm的api,以及定义存放音频设备信息的实体,最后通过调用api实现枚举设备功能。

    1、添加依赖

    由于编写dllimport比较麻烦,而且nuget已经有封装好的库,所以没必要重复造轮子,直接nuget安装然后补充一些必要的接口即可。

    (1)、nuget安装winmm的封装库

    在这里插入图片描述

    (2)、补充接口

    由于Vanara.PInvoke.Multimedia对waveInGetDevCaps和waveOutGetDevCaps导入的有点问题,所以需要自己dllimport。还需要添加一些相关的枚举用于获取声音格式。

    [DllImport("winmm.dll")]
    public static extern MMRESULT waveInGetDevCapsW(uint uDeviceID, out WAVEINCAPS pwic, uint cbwic);
    [DllImport("winmm.dll")]
    public static extern MMRESULT waveOutGetDevCapsW(uint uDeviceID, out WAVEOUTCAPS pwoc, uint cbwoc);
    public enum DWFormats
    {
        WAVE_INVALIDFORMAT = 0x00000000,     /* invalid format */
        WAVE_FORMAT_1M08 = 0x00000001,    /* 11.025 kHz, Mono,   8-bit  */
        WAVE_FORMAT_1S08 = 0x00000002,    /* 11.025 kHz, Stereo, 8-bit  */
        WAVE_FORMAT_1M16 = 0x00000004,    /* 11.025 kHz, Mono,   16-bit */
        WAVE_FORMAT_1S16 = 0x00000008,    /* 11.025 kHz, Stereo, 16-bit */
        WAVE_FORMAT_2M08 = 0x00000010,    /* 22.05  kHz, Mono,   8-bit  */
        WAVE_FORMAT_2S08 = 0x00000020,    /* 22.05  kHz, Stereo, 8-bit  */
        WAVE_FORMAT_2M16 = 0x00000040,    /* 22.05  kHz, Mono,   16-bit */
        WAVE_FORMAT_2S16 = 0x00000080,    /* 22.05  kHz, Stereo, 16-bit */
        WAVE_FORMAT_4M08 = 0x00000100,    /* 44.1   kHz, Mono,   8-bit  */
        WAVE_FORMAT_4S08 = 0x00000200,    /* 44.1   kHz, Stereo, 8-bit  */
        WAVE_FORMAT_4M16 = 0x00000400,    /* 44.1   kHz, Mono,   16-bit */
        WAVE_FORMAT_4S16 = 0x00000800,    /* 44.1   kHz, Stereo, 16-bit */
        WAVE_FORMAT_44M08 = 0x00000100,     /* 44.1   kHz, Mono,   8-bit  */
        WAVE_FORMAT_44S08 = 0x00000200,     /* 44.1   kHz, Stereo, 8-bit  */
        WAVE_FORMAT_44M16 = 0x00000400,     /* 44.1   kHz, Mono,   16-bit */
        WAVE_FORMAT_44S16 = 0x00000800,     /* 44.1   kHz, Stereo, 16-bit */
        WAVE_FORMAT_48M08 = 0x00001000,     /* 48     kHz, Mono,   8-bit  */
        WAVE_FORMAT_48S08 = 0x00002000,     /* 48     kHz, Stereo, 8-bit  */
        WAVE_FORMAT_48M16 = 0x00004000,     /* 48     kHz, Mono,   16-bit */
        WAVE_FORMAT_48S16 = 0x00008000,     /* 48     kHz, Stereo, 16-bit */
        WAVE_FORMAT_96M08 = 0x00010000,     /* 96     kHz, Mono,   8-bit  */
        WAVE_FORMAT_96S08 = 0x00020000,     /* 96     kHz, Stereo, 8-bit  */
        WAVE_FORMAT_96M16 = 0x00040000,     /* 96     kHz, Mono,   16-bit */
        WAVE_FORMAT_96S16 = 0x00080000,     /* 96     kHz, Stereo, 16-bit */
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    2、定义实体

    需要定义声音格式

    class SampleFormat
    {
        /// 
        /// 声道数
        /// 
        public ushort Channels { set; get; }
        /// 
        /// 采样率
        /// 
        public uint SampleRate { set; get; }
        /// 
        /// 位深
        /// 
        public ushort BitsPerSample { set; get; }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    以及声音设备实体

    class AudioDevice
    {
        /// 
        /// 设备Id
        /// 
        public uint Id { set; get; }
        /// 
        /// 设备名称
        /// 
        public string Name { set; get; } = "";
        /// 
        /// 声道数
        /// 
        public int Channels { set; get; }
        /// 
        /// 支持的格式
        /// 
        public IEnumerable<SampleFormat>? SupportedFormats { set; get; }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3、实现枚举

    音频采集设备

    /// 
    /// 枚举声音采集设备
    /// 
    public static IEnumerable<AudioDevice> WaveInDevices
    {
        get
        {
            var deviceCount = waveInGetNumDevs();
            for (uint i = 0; i < deviceCount; i++)
            {
                var sd = GetWaveInDeviceById(i);
                if (sd != null) yield return sd;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    /// 
    /// 通过id获取声音采集设备信息
    /// 
    /// 设备id
    /// 设备对象
    public static AudioDevice? GetWaveInDeviceById(uint id)
    {
        WAVEINCAPS pwic;//声音设备功能信息
        var result = waveInGetDevCapsW(id, out pwic, (uint)Marshal.SizeOf<WAVEINCAPS>());
        if (result != MMRESULT.MMSYSERR_NOERROR) return null;
        AudioDevice sd = new AudioDevice();
        sd.Id = id;
        sd.Channels = pwic.wChannels;
        sd.Name = pwic.szPname;
        sd.SupportedFormats = _GetSurportFormats(pwic.dwFormats);
        return sd;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    音频播放设备

     /// 
     /// 枚举声音播放设备
     /// 
     public static IEnumerable<AudioDevice> WaveOutDevices
     {
         get
         {
             var deviceCount = waveOutGetNumDevs();
             for (uint i = 0; i < deviceCount; i++)
             {
                 var sd = GetWaveOutDeviceById(i);
                 if (sd != null) yield return sd;
             }
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    /// 
    /// 通过id获取声音播放设备信息
    /// 
    /// 设备id
    /// 设备对象
    public static AudioDevice? GetWaveOutDeviceById(uint id)
    {
        WAVEOUTCAPS pwic;//声音设备功能信息
        var result = waveOutGetDevCapsW(id, out pwic, (uint)Marshal.SizeOf<WAVEOUTCAPS>());
        if (result != MMRESULT.MMSYSERR_NOERROR) return null;
        AudioDevice sd = new AudioDevice();
        sd.Id = id;
        sd.Channels = pwic.wChannels;
        sd.Name = pwic.szPname;
        sd.SupportedFormats = _GetSurportFormats(pwic.dwFormats);
        return sd;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    二、完整代码

    .net 7.0

    using System.Runtime.InteropServices;
    using static Vanara.PInvoke.WinMm;
    /************************************************************************
    * @Project:  	AC::Winmm
    * @Decription:  音频设备枚举
    * @Verision:  	v1.0.0.0
    * @Author:  	Xin Nie
    * @Create:  	2023/10/8 09:27:00
    * @LastUpdate:  2023/10/8 15:04:00
    ************************************************************************
    * Copyright @ 2025. All rights reserved.
    ************************************************************************/
    namespace AC
    {
        class Winmm
        {
            /// 
            /// 枚举声音采集设备
            /// 
            public static IEnumerable<AudioDevice> WaveInDevices
            {
                get
                {
                    var deviceCount = waveInGetNumDevs();
                    for (uint i = 0; i < deviceCount; i++)
                    {
                        var sd = GetWaveInDeviceById(i);
                        if (sd != null) yield return sd;
                    }
                }
            }
    
            /// 
            /// 枚举声音播放设备
            /// 
            public static IEnumerable<AudioDevice> WaveOutDevices
            {
                get
                {
                    var deviceCount = waveOutGetNumDevs();
                    for (uint i = 0; i < deviceCount; i++)
                    {
                        var sd = GetWaveOutDeviceById(i);
                        if (sd != null) yield return sd;
                    }
                }
            }
    
            /// 
            /// 通过id获取声音采集设备信息
            /// 
            /// 设备id
            /// 设备对象
            public static AudioDevice? GetWaveInDeviceById(uint id)
            {
                WAVEINCAPS pwic;//声音设备功能信息
                var result = waveInGetDevCapsW(id, out pwic, (uint)Marshal.SizeOf<WAVEINCAPS>());
                if (result != MMRESULT.MMSYSERR_NOERROR) return null;
                AudioDevice sd = new AudioDevice();
                sd.Id = id;
                sd.Channels = pwic.wChannels;
                sd.Name = pwic.szPname;
                sd.SupportedFormats = _GetSurportFormats(pwic.dwFormats);
                return sd;
            }
            /// 
            /// 通过id获取声音播放设备信息
            /// 
            /// 设备id
            /// 设备对象
            public static AudioDevice? GetWaveOutDeviceById(uint id)
            {
                WAVEOUTCAPS pwic;//声音设备功能信息
                var result = waveOutGetDevCapsW(id, out pwic, (uint)Marshal.SizeOf<WAVEOUTCAPS>());
                if (result != MMRESULT.MMSYSERR_NOERROR) return null;
                AudioDevice sd = new AudioDevice();
                sd.Id = id;
                sd.Channels = pwic.wChannels;
                sd.Name = pwic.szPname;
                sd.SupportedFormats = _GetSurportFormats(pwic.dwFormats);
                return sd;
            }
            static List<SampleFormat> _GetSurportFormats(uint foramts)
            {
                var sfs = new List<SampleFormat>();
                foreach (var j in Enum.GetValues<DWFormats>())
                {
                    if ((foramts & (uint)j) != 0)
                    {
                        var name = Enum.GetName(j)!.Split("_").Last();
                        var sp = name.Substring(0, name.Length - 3);
                        var ch = name.Substring(name.Length - 3, 1);
                        var bp = name.Substring(name.Length - 2, 2);
                        uint isp = 0;
                        switch (sp)
                        {
                            case "1": isp = 11025; break;
                            case "2": isp = 22050; break;
                            case "4": isp = 44100; break;
                            case "44": isp = 44100; break;
                            case "48": isp = 48000; break;
                            case "96": isp = 96000; break;
                        }
                        sfs.Add(new SampleFormat() { Channels = (ushort)(ch == "S" ? 1 : 2), SampleRate = isp, BitsPerSample = ushort.Parse(bp) });
                    }
                }
                return sfs;
            }
    
            public enum DWFormats
            {
                WAVE_INVALIDFORMAT = 0x00000000,     /* invalid format */
                WAVE_FORMAT_1M08 = 0x00000001,    /* 11.025 kHz, Mono,   8-bit  */
                WAVE_FORMAT_1S08 = 0x00000002,    /* 11.025 kHz, Stereo, 8-bit  */
                WAVE_FORMAT_1M16 = 0x00000004,    /* 11.025 kHz, Mono,   16-bit */
                WAVE_FORMAT_1S16 = 0x00000008,    /* 11.025 kHz, Stereo, 16-bit */
                WAVE_FORMAT_2M08 = 0x00000010,    /* 22.05  kHz, Mono,   8-bit  */
                WAVE_FORMAT_2S08 = 0x00000020,    /* 22.05  kHz, Stereo, 8-bit  */
                WAVE_FORMAT_2M16 = 0x00000040,    /* 22.05  kHz, Mono,   16-bit */
                WAVE_FORMAT_2S16 = 0x00000080,    /* 22.05  kHz, Stereo, 16-bit */
                WAVE_FORMAT_4M08 = 0x00000100,    /* 44.1   kHz, Mono,   8-bit  */
                WAVE_FORMAT_4S08 = 0x00000200,    /* 44.1   kHz, Stereo, 8-bit  */
                WAVE_FORMAT_4M16 = 0x00000400,    /* 44.1   kHz, Mono,   16-bit */
                WAVE_FORMAT_4S16 = 0x00000800,    /* 44.1   kHz, Stereo, 16-bit */
                WAVE_FORMAT_44M08 = 0x00000100,     /* 44.1   kHz, Mono,   8-bit  */
                WAVE_FORMAT_44S08 = 0x00000200,     /* 44.1   kHz, Stereo, 8-bit  */
                WAVE_FORMAT_44M16 = 0x00000400,     /* 44.1   kHz, Mono,   16-bit */
                WAVE_FORMAT_44S16 = 0x00000800,     /* 44.1   kHz, Stereo, 16-bit */
                WAVE_FORMAT_48M08 = 0x00001000,     /* 48     kHz, Mono,   8-bit  */
                WAVE_FORMAT_48S08 = 0x00002000,     /* 48     kHz, Stereo, 8-bit  */
                WAVE_FORMAT_48M16 = 0x00004000,     /* 48     kHz, Mono,   16-bit */
                WAVE_FORMAT_48S16 = 0x00008000,     /* 48     kHz, Stereo, 16-bit */
                WAVE_FORMAT_96M08 = 0x00010000,     /* 96     kHz, Mono,   8-bit  */
                WAVE_FORMAT_96S08 = 0x00020000,     /* 96     kHz, Stereo, 8-bit  */
                WAVE_FORMAT_96M16 = 0x00040000,     /* 96     kHz, Mono,   16-bit */
                WAVE_FORMAT_96S16 = 0x00080000,     /* 96     kHz, Stereo, 16-bit */
            }
    
            [DllImport("winmm.dll")]
            public static extern MMRESULT waveInGetDevCapsW(uint uDeviceID, out WAVEINCAPS pwic, uint cbwic);
    
            [DllImport("winmm.dll")]
            public static extern MMRESULT waveOutGetDevCapsW(uint uDeviceID, out WAVEOUTCAPS pwoc, uint cbwoc);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145

    三、使用示例

    foreach (var i in Winmm.WaveInDevices)
    {
        Console.WriteLine("音频采集设备" + i.Id + ":" + i.Name);
    }
    foreach (var i in Winmm.WaveOutDevices)
    {    
        Console.WriteLine("音频播放设备"+i.Id+":" +i.Name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述


    总结

    以上就是今天要讲的内容,使用winnm枚举设备还是比较简单的,唯一麻烦一点的地方就是支持格式的获取,但是通过C#使用字符串处理,实现也变得很简单。总的来说,这算是一种获取音频设备信息的方法,能够满足一些使用场景的需求。

  • 相关阅读:
    ghidra
    【跨境电商】全渠道客户服务终极指南(一):概念,重要性与优势
    Java│蓝桥杯省赛真题星期一问题
    【Prometheus】 Grafana数据与可视化
    服务器断电重启后报XFS文件系统错误 XFS (dm-0)_ Metadata I_O error
    Eviews用向量自回归模型VAR实证分析公路交通通车里程与经济发展GDP协整关系时间序列数据和脉冲响应可视化...
    为什么写作
    中标麒麟国产服务器安装MinIO报错不能读取该二进制文件解决方案
    5. Longest Palindromic Substring
    聚焦酷开科技智能大屏OS Coolita,打造智能推荐服务能力全景
  • 原文地址:https://blog.csdn.net/u013113678/article/details/133683982