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 */ }
2、定义实体
需要定义声音格式
class SampleFormat { /// <summary> /// 声道数 /// </summary> public ushort Channels { set; get; } /// <summary> /// 采样率 /// </summary> public uint SampleRate { set; get; } /// <summary> /// 位深 /// </summary> public ushort BitsPerSample { set; get; } };
以及声音设备实体
class AudioDevice { /// <summary> /// 设备Id /// </summary> public uint Id { set; get; } /// <summary> /// 设备名称 /// </summary> public string Name { set; get; } = ""; /// <summary> /// 声道数 /// </summary> public int Channels { set; get; } /// <summary> /// 支持的格式 /// </summary> public IEnumerable<SampleFormat>? SupportedFormats { set; get; } };
3、实现枚举
音频采集设备
/// <summary> /// 枚举声音采集设备 /// </summary> 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; } } }
/// <summary> /// 通过id获取声音采集设备信息 /// </summary> /// <param name="id">设备id</param> /// <returns>设备对象</returns> 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; }
音频播放设备
/// <summary> /// 枚举声音播放设备 /// </summary> 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; } } }
/// <summary> /// 通过id获取声音播放设备信息 /// </summary> /// <param name="id">设备id</param> /// <returns>设备对象</returns> 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; }
二、完整代码
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 { /// <summary> /// 枚举声音采集设备 /// </summary> 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; } } } /// <summary> /// 枚举声音播放设备 /// </summary> 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; } } } /// <summary> /// 通过id获取声音采集设备信息 /// </summary> /// <param name="id">设备id</param> /// <returns>设备对象</returns> 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; } /// <summary> /// 通过id获取声音播放设备信息 /// </summary> /// <param name="id">设备id</param> /// <returns>设备对象</returns> 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); } }
三、使用示例
foreach (var i in Winmm.WaveInDevices) { Console.WriteLine("音频采集设备" + i.Id + ":" + i.Name); } foreach (var i in Winmm.WaveOutDevices) { Console.WriteLine("音频播放设备"+i.Id+":" +i.Name); }
总结
以上就是今天要讲的内容,使用winnm枚举设备还是比较简单的,唯一麻烦一点的地方就是支持格式的获取,但是通过C#使用字符串处理,实现也变得很简单。总的来说,这算是一种获取音频设备信息的方法,能够满足一些使用场景的需求。
到此这篇关于C#通过实现winmm枚举音频设备的文章就介绍到这了,更多相关C# winmm枚举音频设备内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
DevExpress之ChartControl实现柱状图演示实例
这篇文章主要介绍了DevExpress中ChartControl实现柱状图演示方法,实例展示了相关绘图函数的具体用法,具有一定的实用价值,需要的朋友可以参考下2014-10-10
最新评论