目录
概述
AudioRecorder 是 SimpleAudioPlayer 提供的录音组件,与 AudioPlayer 同属 SimpleAudio 命名空间。它使用本机音频 API 从麦克风或其他输入设备捕获音频数据,支持多种输出格式。
using SimpleAudioPlayer;
// 创建录音机
using var recorder = new AudioRecorder();
// 开始录制到文件
recorder.Start(@"C:\Recordings\test.wav");
// 停止录制
recorder.Stop();核心功能:
支持 WAV、AAC (ADTS)、M4A、Raw PCM 四种输出格式
输出到文件或任意
Stream录制统计信息(帧数、丢帧数)
模拟录制模式(测试用,不依赖麦克风硬件)
跨平台兼容
AudioRecorder 快速入门
录制到 WAV 文件
WAV 是最简单、兼容性最好的格式,不需要编码器,所有平台都支持:
using SimpleAudioPlayer;
using var recorder = new AudioRecorder();
Console.WriteLine("开始录音... 按 Enter 停止");
recorder.Start(@"C:\Recordings\my_audio.wav");
Console.ReadLine();
recorder.Stop();
Console.WriteLine("录音已保存到 C:\\Recordings\\my_audio.wav");录制参数: Start(filename) 使用默认参数(44.1kHz, 16-bit, mono)。
录制到 AAC 文件
AAC 格式需要编码器,文件体积更小:
using SimpleAudioPlayer;
using var recorder = new AudioRecorder();
recorder.Start(@"C:\Recordings\my_audio.aac");
Console.WriteLine("正在录制 AAC...");
Thread.Sleep(5000); // 录制 5 秒
recorder.Stop();
Console.WriteLine("录音完成");输出格式详解
设置输出格式
// 设置格式后再开始录制
recorder.OutputFormat = RecordingFileFormat.Wav; // WAV
recorder.OutputFormat = RecordingFileFormat.Aac; // AAC (ADTS)
recorder.OutputFormat = RecordingFileFormat.M4A; // M4A (AAC in MP4)
recorder.OutputFormat = RecordingFileFormat.Pcm; // Raw PCM格式对比
格式 | 文件扩展名 | 有损/无损 | 编码器需求 | 兼容性 | 文件大小 | 适用场景 |
|---|---|---|---|---|---|---|
WAV | .wav | 无损 (PCM) | 无 | 极高 | 大 | 录音编辑、存档 |
AAC (ADTS) | .aac | 有损 | FFmpeg | 高 | 小 | 语音笔记、播客 |
M4A | .m4a | 有损 | FFmpeg | 高 | 小 | 移动设备分享 |
Raw PCM | .raw | 无损 (PCM) | 无 | 低(无头) | 大 | 自定义处理 |
设置采样率和声道
// 录制前配置参数
recorder.SampleRate = 48000; // 48kHz
recorder.Channels = 2; // 立体声
recorder.BitDepth = 16; // 16-bit
recorder.OutputFormat = RecordingFileFormat.Wav;
recorder.Start(@"C:\Recordings\high_quality.wav");推荐的录音配置:
场景 | 采样率 | 声道 | 位深 | 格式 |
|---|---|---|---|---|
语音笔记 | 16000 | Mono | 16 | WAV 或 AAC |
播客录制 | 44100 | Mono | 16 | WAV |
音乐录制 | 48000 | Stereo | 24 | WAV |
移动分享 | 44100 | Stereo | 16 | M4A |
语音识别 | 16000 | Mono | 16 | WAV |
自定义后处理 | 48000 | Stereo | 24 | Raw PCM |
录制到流
除了保存到文件,还可以录制到任意 Stream 对象:
using SimpleAudioPlayer;
using var outputStream = new MemoryStream();
using var recorder = new AudioRecorder();
// 录制到流(需要指定格式)
recorder.OutputFormat = RecordingFileFormat.Wav;
recorder.Start(outputStream, RecordingFileFormat.Wav);
Console.WriteLine("正在录音到内存流... 按 Enter 停止");
Console.ReadLine();
recorder.Stop();
// 此时 outputStream 包含完整的 WAV 文件数据
Console.WriteLine($"录制了 {outputStream.Length} 字节");
// 可以保存或进一步处理
await File.WriteAllBytesAsync(@"C:\Recordings\from_stream.wav", outputStream.ToArray());流的优势:
录制到
MemoryStream直接用于播放或上传录制到
FileStream实现自定义文件名逻辑录制到
NetworkStream实时传输音频录制到
CryptoStream加密保存
上传到服务器的示例
using SimpleAudioPlayer;
// 在内存中录制
using var audioStream = new MemoryStream();
using var recorder = new AudioRecorder();
recorder.OutputFormat = RecordingFileFormat.Aac;
recorder.Start(audioStream, RecordingFileFormat.Aac);
Console.WriteLine("录音中... 按 Enter 停止并上传");
Console.ReadLine();
recorder.Stop();
// 上传到服务器
audioStream.Position = 0;
using var httpClient = new HttpClient();
using var content = new StreamContent(audioStream);
content.Headers.ContentType = new MediaTypeHeaderValue("audio/aac");
var response = await httpClient.PostAsync("https://api.example.com/upload", content);
Console.WriteLine($"上传结果: {response.StatusCode}");停止录制与统计信息
Stop() 返回一个 MaResult 对象,包含录制统计信息:
using SimpleAudioPlayer;
using var recorder = new AudioRecorder();
recorder.Start(@"C:\Recordings\stats.wav");
Thread.Sleep(3000);
var result = recorder.Stop();
Console.WriteLine($"录制统计:");
Console.WriteLine($" 采样率: {result.SampleRate} Hz");
Console.WriteLine($" 声道数: {result.Channels}");
Console.WriteLine($" 位深: {result.BitsPerSample}");
Console.WriteLine($" 总帧数: {result.TotalFrames}");
Console.WriteLine($" 丢帧数: {result.FramesDropped}");
Console.WriteLine($" 时长: {result.Duration}");
if (result.FramesDropped > 0)
{
double dropRate = (double)result.FramesDropped / result.TotalFrames * 100;
Console.WriteLine($" ⚠ 注意: 丢帧率 {dropRate:F2}%,可能存在录音质量问题");
}MaResult 属性
属性 | 类型 | 说明 |
|---|---|---|
|
| 录制采样率 (Hz) |
|
| 声道数 |
|
| 位深 |
|
| 采集的 PCM 帧总数 |
|
| 丢帧数(因缓冲区溢出丢失的帧) |
|
| 录制时长 |
|
| 输出文件路径(如果录制到文件) |
模拟录制模式
模拟录制模式不需要麦克风硬件,在测试环境中非常有用。它生成静音 PCM 数据,让你可以在没有音频输入设备的机器上测试录制流程。
using SimpleAudioPlayer;
// 启用模拟录制模式(必须在 Start 之前设置)
AudioRecorder.SimulateRecording = true;
using var recorder = new AudioRecorder();
recorder.OutputFormat = RecordingFileFormat.Wav;
recorder.Start(@"C:\Recordings\test_simulated.wav");
Thread.Sleep(3000);
var result = recorder.Stop();
Console.WriteLine($"模拟录制完成,时长: {result.Duration}");
// 测试完成后关闭模拟模式
AudioRecorder.SimulateRecording = false;模拟录制适用场景:
CI/CD 流水线中测试录音功能
没有麦克风的开发环境
录制功能的单元测试
UI 自动化测试
在测试中使用
[Fact]
public void TestRecordingAndPlayback()
{
// 启用模拟模式
AudioRecorder.SimulateRecording = true;
var recorder = new AudioRecorder();
var player = new AudioPlayer();
using var audioStream = new MemoryStream();
// 模拟录制 2 秒
recorder.OutputFormat = RecordingFileFormat.Wav;
recorder.Start(audioStream, RecordingFileFormat.Wav);
Thread.Sleep(2000);
recorder.Stop();
// 验证录制结果
var result = recorder.Stop();
Assert.True(result.TotalFrames > 0);
Assert.Equal(0, result.FramesDropped);
// 回放录制的音频
audioStream.Position = 0;
var handle = new StreamHandle(audioStream);
player.Load(handle);
player.Play();
AudioRecorder.SimulateRecording = false;
}完整示例:录音并回放
以下程序录制一段音频、保存到文件、然后立即回放:
using SimpleAudioPlayer;
Console.WriteLine("SimpleAudioPlayer 录音与回放示例");
Console.WriteLine("====================================");
Console.WriteLine();
// 选择输出格式
Console.WriteLine("选择输出格式:");
Console.WriteLine(" 1. WAV (无损)");
Console.WriteLine(" 2. AAC (有损,体积小)");
Console.WriteLine(" 3. M4A (AAC in MP4)");
Console.Write("请选择 (1-3) [默认 1]: ");
var formatChoice = Console.ReadKey(true);
AudioOutputFormat format = RecordingFileFormat.Wav;
string extension = ".wav";
switch (formatChoice.KeyChar)
{
case '2':
format = RecordingFileFormat.Aac;
extension = ".aac";
Console.WriteLine("AAC 格式");
break;
case '3':
format = RecordingFileFormat.M4A;
extension = ".m4a";
Console.WriteLine("M4A 格式");
break;
default:
Console.WriteLine("WAV 格式");
break;
}
// 选择录音配置
Console.WriteLine();
Console.WriteLine("选择录音质量:");
Console.WriteLine(" 1. 语音 (16kHz, Mono, 16-bit)");
Console.WriteLine(" 2. 标准 (44.1kHz, Mono, 16-bit)");
Console.WriteLine(" 3. 高保真 (48kHz, Stereo, 24-bit)");
Console.Write("请选择 (1-3) [默认 2]: ");
var qualityChoice = Console.ReadKey(true);
int sampleRate = 44100;
int channels = 1;
int bitDepth = 16;
switch (qualityChoice.KeyChar)
{
case '1':
sampleRate = 16000;
Console.WriteLine("语音质量");
break;
case '3':
sampleRate = 48000;
channels = 2;
bitDepth = 24;
Console.WriteLine("高保真质量");
break;
default:
Console.WriteLine("标准质量");
break;
}
// 生成输出文件名
string outputDir = @"C:\Recordings";
Directory.CreateDirectory(outputDir);
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string outputPath = Path.Combine(outputDir, $"recording_{timestamp}{extension}");
Console.WriteLine();
Console.WriteLine($"输出文件: {outputPath}");
Console.WriteLine($"格式: {format}, 采样率: {sampleRate}Hz, 声道: {(channels == 1 ? "Mono" : "Stereo")}, 位深: {bitDepth}");
Console.WriteLine();
Console.WriteLine("准备就绪!按 Enter 开始录音...");
Console.ReadLine();
// 创建录音机并配置
using var recorder = new AudioRecorder();
recorder.SampleRate = sampleRate;
recorder.Channels = channels;
recorder.BitDepth = bitDepth;
recorder.OutputFormat = format;
// 开始录音
Console.WriteLine("正在录音... 按 Enter 停止");
recorder.Start(outputPath);
// 显示录音时长
var startTime = DateTime.Now;
var cts = new CancellationTokenSource();
_ = Task.Run(async () =>
{
while (!cts.IsCancellationRequested)
{
var elapsed = DateTime.Now - startTime;
Console.Write($"\r录音中... {elapsed:mm\\:ss\\.ff}");
await Task.Delay(100);
}
});
Console.ReadLine();
cts.Cancel();
// 停止录音
var result = recorder.Stop();
Console.WriteLine();
Console.WriteLine("=== 录音统计 ===");
Console.WriteLine($" 时长: {result.Duration}");
Console.WriteLine($" 总帧数: {result.TotalFrames:N0}");
Console.WriteLine($" 丢帧数: {result.FramesDropped:N0}");
Console.WriteLine($" 文件大小: {new FileInfo(outputPath).Length / 1024.0:F1} KB");
Console.WriteLine();
// 询问是否回放
Console.Write("是否立即回放?(Y/N) [默认 Y]: ");
var playKey = Console.ReadKey(true);
Console.WriteLine();
if (playKey.KeyChar != 'n' && playKey.KeyChar != 'N')
{
Console.WriteLine("正在回放录音...");
using var player = new AudioPlayer();
player.PlaybackStateChanged += (s, e) =>
{
if (e.NewState == PlaybackState.Completed)
{
Console.WriteLine("回放完成");
}
};
player.PlayCompleted += (s, e) =>
{
Console.WriteLine("播放完毕");
};
try
{
player.Load(outputPath);
Console.WriteLine($"音频时长: {player.Duration}");
player.Play();
Console.WriteLine("按 Enter 停止回放");
Console.ReadLine();
player.Stop();
}
catch (Exception ex)
{
Console.WriteLine($"回放失败: {ex.Message}");
}
}
Console.WriteLine("程序结束。");录制过程中的错误处理
常见异常及处理
using SimpleAudioPlayer;
using var recorder = new AudioRecorder();
try
{
recorder.Start(@"C:\Recordings\test.wav");
// ... 录制逻辑
recorder.Stop();
}
catch (InvalidOperationException ex)
{
// 已在录制中 / 未初始化
Console.WriteLine($"录制状态错误: {ex.Message}");
}
catch (UnauthorizedAccessException ex)
{
// 没有麦克风权限
Console.WriteLine($"权限不足: {ex.Message}");
Console.WriteLine("请在系统设置中授予麦克风权限。");
}
catch (NotSupportedException ex)
{
// 不支持当前配置(如不支持的采样率)
Console.WriteLine($"不支持的配置: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"录制失败: {ex.Message}");
}权限检查
不同平台对麦克风权限的处理不同:
// 尝试录制一小段来检测权限
public static async Task<bool> CheckMicrophonePermissionAsync()
{
try
{
AudioRecorder.SimulateRecording = false;
using var recorder = new AudioRecorder();
using var stream = new MemoryStream();
recorder.OutputFormat = RecordingFileFormat.Wav;
recorder.Start(stream, RecordingFileFormat.Wav);
await Task.Delay(500);
recorder.Stop();
return stream.Length > 44; // 有效的 WAV 文件至少有 44 字节头
}
catch
{
return false;
}
}丢帧处理
丢帧通常表示缓冲区太小或 CPU 负载过高:
using var recorder = new AudioRecorder();
// 增大缓冲区可以降低丢帧率
// (具体 API 取决于版本实现)
recorder.Start(@"C:\Recordings\test.wav");
Thread.Sleep(5000);
var result = recorder.Stop();
if (result.FramesDropped > 0)
{
double dropRate = (double)result.FramesDropped / result.TotalFrames * 100;
if (dropRate > 5)
{
Console.WriteLine($"警告:丢帧率 {dropRate:F1}%,建议降低采样率或升级硬件。");
}
}平台注意事项
Windows
使用 WASAPI 捕获设备
默认使用默认输入设备(可在系统设置中更改)
需要麦克风权限(Windows 10/11 隐私设置)
独占模式下可能影响其他应用的录音能力
配置默认输入设备:
// Windows 上选择特定输入设备(如果 API 支持)
// recorder.InputDeviceId = "device_id"; // 取决于具体版本实现Linux
使用 ALSA 或 PulseAudio 进行捕获
PulseAudio 默认提供混音和采样率转换
需要
pulseaudio-utils或alsa-utils可能需要将用户加入
audio组
# Linux 上可能需要的配置
sudo usermod -a -G audio $USERmacOS
使用 CoreAudio 进行音频捕获
需要在
Info.plist中声明麦克风权限macOS 10.14+ 要求麦克风权限,系统会弹出授权对话框
权限可在「系统偏好设置 → 安全性与隐私 → 麦克风」中管理
Info.plist 配置:
<key>NSMicrophoneUsageDescription</key>
<string>此应用需要访问麦克风以录制音频。</string>Android
Android 6.0+ (API 23+) 需要运行时权限
Android 10+ (API 29+) 使用 AAudio 提供低延迟录制
部分设备可能不支持某些采样率
Android 权限请求:
// Xamarin.Android / .NET MAUI 中的权限请求
var status = await Permissions.RequestAsync<Permissions.Microphone>();
if (status != PermissionStatus.Granted)
{
Console.WriteLine("未获得麦克风权限");
return;
}进阶用法
分段录制
using SimpleAudioPlayer;
using var recorder = new AudioRecorder();
recorder.OutputFormat = RecordingFileFormat.Wav;
for (int i = 1; i <= 3; i++)
{
string fileName = $"C:\\Recordings\\segment_{i}.wav";
Console.WriteLine($"录制第 {i} 段...");
recorder.Start(fileName);
Thread.Sleep(3000);
recorder.Stop();
Console.WriteLine($"第 {i} 段已保存: {fileName}");
}检测是否正在录制
if (recorder.IsRecording)
{
Console.WriteLine("正在录制中...");
var result = recorder.Stop();
}Raw PCM 后处理
录制为 Raw PCM 后可以自定义处理:
recorder.OutputFormat = RecordingFileFormat.Pcm;
recorder.Start(@"C:\Recordings\raw_output.pcm");
Thread.Sleep(3000);
var result = recorder.Stop();
Console.WriteLine($"Raw PCM 数据: {result.TotalFrames} 帧");
Console.WriteLine($"参数: {result.SampleRate}Hz, {result.Channels}ch, {result.BitsPerSample}bit");
// Raw PCM 需要知道参数才能正确播放或转换
// 可使用外部工具(如 ffmpeg)转换为 WAV
// ffmpeg -f s16le -ar 44100 -ac 1 -i raw_output.pcm output.wav通过本文的学习,你应该能够使用 AudioRecorder 完成各种录音任务。下一章将对比 SimpleAudioPlayer 与其他音频库的优劣,帮助你在项目中做出最佳选择。
发表评论