C#控制台程序基于NAudio实现音频转字节数组及无头字节数组转音频
在控制台应用中用NAudio实现麦克风录制→字节数组→播放
我直接给你梳理完整的实现方案,结合你已有的代码补充关键逻辑,都是控制台环境能直接跑的:
一、先完善录制逻辑,捕获音频到字节数组
你现有的启动录制代码只是开启了麦克风,但没捕获音频数据。我们需要加个MemoryStream来存录制的原始数据,再通过WaveInEvent的DataAvailable事件把每次的音频缓冲区数据写入流,最后转成字节数组。
修改后的代码片段:
// 用来临时存储录制的音频数据 private MemoryStream _recordedAudioStream = new MemoryStream(); private WaveInEvent _audioSource = null; // 你的设备获取逻辑保持不变 private List<WaveInCapabilities> _sources = new List<WaveInCapabilities>(); public List<string> Devices = new List<string>(); public List<string> Channels = new List<string>(); public void GetMicDevices() { for(int i = 0; i < WaveIn.DeviceCount; i++) { _sources.Add(WaveIn.GetCapabilities(i)); } foreach(var device in _sources) { Devices.Add(device.ProductName); Channels.Add(device.Channels.ToString()); } } public void StartMicRecording() { // 重置存储流,避免残留旧数据 if (_recordedAudioStream != null) { _recordedAudioStream.Dispose(); _recordedAudioStream = new MemoryStream(); } int targetDeviceNum = 0; // 可改成用户选择的设备编号 _audioSource = new WaveInEvent(); _audioSource.DeviceNumber = targetDeviceNum; // 明确指定WaveFormat(采样率44100、16位深度、对应设备的通道数) var deviceCaps = WaveIn.GetCapabilities(targetDeviceNum); _audioSource.WaveFormat = new WaveFormat(44100, 16, deviceCaps.Channels); // 订阅数据捕获事件 _audioSource.DataAvailable += AudioSource_DataAvailable; // 订阅录制停止事件,处理后续逻辑 _audioSource.RecordingStopped += AudioSource_RecordingStopped; _audioSource.StartRecording(); Console.WriteLine("开始录制,按任意键停止..."); Console.ReadKey(); _audioSource.StopRecording(); } private void AudioSource_DataAvailable(object sender, WaveInEventArgs e) { // 把每次收到的音频数据写入内存流 _recordedAudioStream.Write(e.Buffer, 0, e.BytesRecorded); } private void AudioSource_RecordingStopped(object sender, StoppedEventArgs e) { // 录制结束,把内存流转成字节数组 byte[] audioBytes = _recordedAudioStream.ToArray(); Console.WriteLine($"录制完成!音频字节数组长度:{audioBytes.Length}"); // 直接调用播放方法测试 PlayAudioFromBytes(audioBytes, _audioSource.WaveFormat); // 清理资源 _audioSource.Dispose(); _recordedAudioStream.Dispose(); }
二、实现从字节数组播放音频
控制台环境用WaveOutEvent就能播放,不需要依赖Windows Forms。我们把字节数组包装成MemoryStream,再用RawSourceWaveStream读取原始PCM数据,最后交给WaveOutEvent播放:
public void PlayAudioFromBytes(byte[] audioBytes, WaveFormat waveFormat) { using (var memoryStream = new MemoryStream(audioBytes)) using (var rawWaveStream = new RawSourceWaveStream(memoryStream, waveFormat)) using (var waveOut = new WaveOutEvent()) { waveOut.Init(rawWaveStream); waveOut.Play(); Console.WriteLine("开始播放录制的音频,等待播放完成..."); // 循环等待播放结束 while (waveOut.PlaybackState == PlaybackState.Playing) { System.Threading.Thread.Sleep(100); } Console.WriteLine("播放结束!"); } }
三、完整控制台示例
把所有逻辑整合到Main方法里,直接就能运行:
class Program { static void Main(string[] args) { var audioManager = new AudioManager(); // 获取并打印可用麦克风设备 audioManager.GetMicDevices(); Console.WriteLine("=== 可用麦克风设备 ==="); for (int i = 0; i < audioManager.Devices.Count; i++) { Console.WriteLine($"{i+1}. {audioManager.Devices[i]} | 通道数:{audioManager.Channels[i]}"); } // 启动录制流程 audioManager.StartMicRecording(); } } // 封装所有音频操作的类 class AudioManager { private MemoryStream _recordedAudioStream = new MemoryStream(); private WaveInEvent _audioSource = null; private List<WaveInCapabilities> _sources = new List<WaveInCapabilities>(); public List<string> Devices = new List<string>(); public List<string> Channels = new List<string>(); public void GetMicDevices() { for(int i = 0; i < WaveIn.DeviceCount; i++) { _sources.Add(WaveIn.GetCapabilities(i)); } foreach(var device in _sources) { Devices.Add(device.ProductName); Channels.Add(device.Channels.ToString()); } } public void StartMicRecording() { if (_recordedAudioStream != null) { _recordedAudioStream.Dispose(); _recordedAudioStream = new MemoryStream(); } int targetDeviceNum = 0; _audioSource = new WaveInEvent(); _audioSource.DeviceNumber = targetDeviceNum; var deviceCaps = WaveIn.GetCapabilities(targetDeviceNum); _audioSource.WaveFormat = new WaveFormat(44100, 16, deviceCaps.Channels); _audioSource.DataAvailable += AudioSource_DataAvailable; _audioSource.RecordingStopped += AudioSource_RecordingStopped; _audioSource.StartRecording(); Console.WriteLine("开始录制,按任意键停止..."); Console.ReadKey(); _audioSource.StopRecording(); } private void AudioSource_DataAvailable(object sender, WaveInEventArgs e) { _recordedAudioStream.Write(e.Buffer, 0, e.BytesRecorded); } private void AudioSource_RecordingStopped(object sender, StoppedEventArgs e) { byte[] audioBytes = _recordedAudioStream.ToArray(); Console.WriteLine($"录制完成!音频字节数组长度:{audioBytes.Length}"); PlayAudioFromBytes(audioBytes, _audioSource.WaveFormat); _audioSource.Dispose(); _recordedAudioStream.Dispose(); } public void PlayAudioFromBytes(byte[] audioBytes, WaveFormat waveFormat) { using (var memoryStream = new MemoryStream(audioBytes)) using (var rawWaveStream = new RawSourceWaveStream(memoryStream, waveFormat)) using (var waveOut = new WaveOutEvent()) { waveOut.Init(rawWaveStream); waveOut.Play(); Console.WriteLine("开始播放录制的音频,等待播放完成..."); while (waveOut.PlaybackState == PlaybackState.Playing) { System.Threading.Thread.Sleep(100); } Console.WriteLine("播放结束!"); } } }
小提示
- 记得先通过NuGet安装NAudio包:
Install-Package NAudio - 运行时Windows会弹窗请求麦克风权限,一定要允许
- 如果想让用户选择不同设备,修改
targetDeviceNum的赋值逻辑就行,比如让用户输入设备编号
内容的提问来源于stack exchange,提问作者Computeshorts
相关产品推荐
相关产品推荐

