关于 matlab-play-record-audio
面向 MATLAB 用户的音频设备 I/O 技能,指导使用 audiostreamer 播放、录音及同步全双工采集,并涵盖回调和设备诊断。需要 Audio Toolbox R2025a 或更高版本。
主要功能
- 01播放、录音与全双工模式
- 02回调驱动的音频流
- 03预缓冲与传输控制
- 04音频设备枚举与选择
- 05延迟和欠载诊断
适用场景
- 01通过声卡播放音频
- 02从麦克风采集音频
- 03执行回环或声学测量
- 04检查可用音频设备
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ matlab/ matlab-agentic-toolkit --skill matlab-play-record-audio安装后在 Claude Code 中输入/matlab-play-record-audio确认已加载。
附带文件manifest.yaml
详细介绍
audiostreamer — MATLAB 音频设备 I/O(R2025a+)
audiostreamer 是 audioDeviceWriter、audioDeviceReader 和 audioPlayerRecorder 的统一替代方案。它提供仅播放、仅录制或全双工模式,并支持回调、预缓冲、传输控制和测量辅助功能。
版本要求: audiostreamer 需要 Audio Toolbox R2025a 或更高版本。start 和 write 方法于 R2026a 中新增。
适用场景
- 通过声卡或 USB 音频设备播放音频
- 从麦克风或音频接口录制音频
- 全双工播放和录制(例如,声学测量、回环测试)
- 列出或选择音频设备和驱动程序
- 在 MATLAB 中涉及音频硬件 I/O 的任何工作流
不适用场景
- 播放单个独立声音 — 对于无需排序、仅播放一次的短音频片段,
sound或soundsc即可。对于顺序播放(例如,前后对比),请使用audiostreamer— 它的play()调用会自动排队,而重叠调用sound会同时播放。 - 代码生成(codegen) —
audiostreamer目前尚不支持 codegen;如果目标是 codegen,请使用旧版 API - Simulink 模型 — Simulink 仍使用现有音频 I/O 模块,而非
audiostreamer - Audio Toolbox 不可用 — 如果用户没有 Audio Toolbox,请改用
sound/soundsc、audioplayer/audiorecorder,或audioDeviceWriter(DSP System Toolbox) - 仅文件 I/O — 无需设备播放或录制的音频文件读写应使用
audioread/audiowrite,而非此工具 - DAQ 硬件 — National Instruments 或类似数据采集设备使用 DAQ Toolbox 和
daq对象 - 仅限 MIDI 的设备 — MIDI 控制使用
mididevice/midicontrols,而非audiostreamer
构造
对 Mode 和 SampleRate 使用名称-值对(也支持位置参数简写,但不支持自动补全):
默认 Mode 为 "player"。如果要录制,必须显式设置 Mode — 设置为 Mode="recorder" 或 Mode="full-duplex"。系统不会根据 Recorder 或 RecorderChannels 等其他属性推断 Mode。
as = audiostreamer % default: player mode, 44100 Hz
as = audiostreamer(Mode="player", SampleRate=fs) % player at fs Hz
as = audiostreamer(Mode="recorder", SampleRate=fs) % recorder at fs Hz
as = audiostreamer(Mode="full-duplex", SampleRate=fs) % simultaneous play + record
as = audiostreamer(Mode="full-duplex", SampleRate=48000, Driver="ASIO", ...
Player="Focusrite USB ASIO", Recorder="Focusrite USB ASIO", ...
PlayerChannels=[1 2], RecorderChannels=[1 2])
属性
设备配置(开始流式传输前设置)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Mode | "player" / "recorder" / "full-duplex" | "player" | 在构造时或通过属性设置 |
Driver | "DirectSound" / "ASIO" / "WASAPI"(Win);"CoreAudio"(Mac);"ALSA"(Linux) | OS 默认值 | 仅在 Windows 上设置(Mac/Linux 各只有一个驱动程序)。构造时设置会选择该驱动程序的默认设备。 |
Player | 字符串 | 该驱动程序的系统默认设备 | 输出设备名称。省略时使用所选驱动程序的默认设备。 |
Recorder | 字符串 | 该驱动程序的系统默认设备 | 输入设备名称。省略时使用所选驱动程序的默认设备。 |
SampleRate | 正标量 | 44100 | Hz |
DeviceBufferSize | 正整数或 "auto" | "auto" | 对 ASIO 固定(使用 asiosettings)。 |
DeviceBitFormat | "single" / "int24" / "int16" | "int24" | ASIO 上的 int16 会静默使用 int24 |
PlayerChannels | 行向量或 "auto" | "auto" | 从 1 开始的通道映射。"auto" 会将单声道升混为立体声;对于 N≥2 个通道,会在设备上打开 N 个通道 |
RecorderChannels | 行向量 | 1 | 从 1 开始的通道映射。默认录制 1 个通道 — 例如,设置为 1:2 可录制立体声 |
ExclusiveMode | 开/关 | "on" | 仅限 WASAPI — 禁用操作系统混音/重采样 |
ConstantLatency | "off" / "dropPlayer" / "dropRecorder" | "off" | 全双工丢帧处理 |
重要: 开始流式传输后,Mode、SampleRate、Driver、DeviceBufferSize、DeviceBitFormat、ExclusiveMode、ConstantLatency、PlayerChannels 和 RecorderChannels 将被锁定。更改这些属性前,请调用 release(as),以避免系统自动释放并发出警告。
回调属性
| 属性 | 签名 | 触发条件 |
|---|---|---|
PlayerFcn | @(obj, event) | Player 缓冲区低于 PlayerMinSamples |
PlayerMinSamples | 正整数(默认值为 16384) | PlayerFcn 的触发阈值 |
RecorderFcn | @(obj, event) | Recorder 缓冲区超过 RecorderMinSamples |
RecorderMinSamples | 正整数(默认值为 1024) | RecorderFcn 的触发阈值 |
PlayerCompletedFcn | @(obj, event) | 输出队列为空 |
RecorderCompletedFcn | @(obj, event) | 定长录音完成 |
PlayerUnderrunFcn | @(obj, event) | Player 发生欠载 |
所有回调都必须恰好接受 2 个参数。 第 1 个参数是 audiostreamer 对象。第 2 个参数是带有 .Type 字段的事件结构体。如果不需要事件,请使用 @(obj, ~)。
不同类型的事件结构体字段:
PlayerFcn:event.Type = "Player",event.NumPlayerSamplesRecorderFcn:event.Type = "Recorder",event.NumRecorderSamplesPlayerCompletedFcn:event.Type = "PlayerCompleted",event.StreamTimeRecorderCompletedFcn:event.Type = "RecorderCompleted",event.StreamTimePlayerUnderrunFcn:event.Type = "PlayerUnderrun",event.SamplesUnderrun
只读状态
| 属性 | 说明 |
|---|---|
NumPlayerSamples | 输出缓冲区中当前排队的采样数 |
NumRecorderSamples | 无需阻塞即可通过 read() 读取的采样数 |
MaxPlayerChannels | 所选设备支持的最大输出通道数 |
MaxRecorderChannels | 所选设备支持的最大输入通道数 |
方法
播放
| 方法 | 说明 |
|---|---|
play(obj, x) | 将 x 加入队列并播放。会阻塞,直到输出缓冲区 ≤ PlayerMinSamples(返回时最多还有 PlayerMinSamples 个采样尚未播放)。最后一次调用 play 后,请调用 waitfor(as),以确保在 release 前完成播放。 |
play(obj, x, "non-blocking") | 将 x 加入队列后立即返回,不受缓冲区大小影响。 |
play(obj) | 启动 PlayerFcn 回调循环(不带数据参数)。 |
write(obj, x) | [R2026a+] 将 x 加入输出缓冲区,但不启动播放。与 start() 配合使用。 |
write(obj, x, "non-blocking") | 将 x 加入队列后立即返回,不受缓冲区大小影响。[R2026a+] |
录音
| 方法 | 说明 |
|---|---|
record(obj) | 无限期开始录音。如果缓冲区中还有未读取的采样,则发出警告。若要避免此情况,请调用 stop(as)(全双工模式下调用 stop(as, "recorder")),然后调用 read(as) 清空缓冲区。如果采样已由回调或 read 读取,则无需执行此操作。 |
record(obj, numSamples) | 录制恰好 numSamples 个采样,然后停止。此方法同样会对未读取的采样发出警告。 |
read(obj) | 立即返回所有可用的录音采样(非阻塞)。如果没有可用采样,则返回空值。 |
read(obj, numSamples) | 会阻塞,直到有 numSamples 个采样可用,然后返回这些采样。 |
全双工
| 方法 | 说明 |
|---|---|
playrec(obj, x) | 同时播放 x 并录音。非阻塞——录音会在后台继续;使用 read 获取数据。 |
playrec(obj, x, numSamples) | 播放 x 并录制 numSamples 个采样。阻塞——返回录制的矩阵。 |
playrec(obj) | 启动由回调驱动的全双工模式(需要 RecorderFcn 和/或 PlayerFcn)。 |
playrec 会暂停 Player 和 Recorder,将音频加入队列,然后同时恢复二者,以实现可重复的延迟。这对使用 impzest 进行测量至关重要。
传输控制
| 方法 | 描述 |
|---|---|
start(obj) | [R2026a+] 以当前模式开始流式传输。 |
start(obj, Mode="player") | [R2026a+] 仅启动播放器(全双工)。 |
start(obj, Mode="recorder", SamplesToRecord=N) | [R2026a+] 启动录音器并录制固定数量的样本。 |
stop(obj) | 停止所有流式传输。保留尚未读取的输入样本。重置欠载计数(getUnderrunCount 也会重置)。 |
stop(obj, "player"/"recorder"/"both") | 停止指定的一侧。 |
pause(obj) / pause(obj, "player"/"recorder"/"both") | 暂停并保留状态。 |
resume(obj) / resume(obj, "player"/"recorder"/"both") | 从暂停状态恢复。 |
waitfor(obj) / waitfor(obj, "player"/"recorder"/"both") | 阻塞,直到操作完成。 |
release(obj) | 停止、刷新、关闭设备并拆除。删除尚未读取的样本。 |
查询 / 诊断
| 方法 | 描述 |
|---|---|
isPlaying(obj) | 返回 OnOffSwitchState |
isRecording(obj) | 返回 OnOffSwitchState |
isPlayerPaused(obj) | 返回 OnOffSwitchState |
isRecorderPaused(obj) | 返回 OnOffSwitchState |
getUnderrunCount(obj) | 返回自上次调用以来的欠载样本数。重置计数器(stop 也会重置)。 |
getStreamTime(obj) | 流式传输经过的时间(秒)。 |
getStreamTime(obj, "reset") | 重置流计时器。 |
measureLoopbackLatency(obj) | 仅适用于全双工和单声道。返回延迟的样本数。 |
静态设备枚举
audiostreamer.getDrivers() % Available drivers for this OS
audiostreamer.getPlayerNames() % All output devices
audiostreamer.getPlayerNames("ASIO") % Output devices for specific driver
audiostreamer.getRecorderNames() % All input devices
audiostreamer.getRecorderNames("ASIO") % Input devices for specific driver
audiostreamer.getAudioDevices() % Struct array: Name, Driver, MaxRecorderChannels, MaxPlayerChannels, SampleRate (channel counts are int32)
注意: getAudioDevices() 返回的 MaxRecorderChannels 和 MaxPlayerChannels 类型为 int32。在 UI 组件(例如 uispinner 的 Limits)中使用这些值,或用于要求 double 的算术运算之前,请先转换为 double()。
重要:没有 setup() 方法
audiostreamer 没有公开的 setup() 方法。设备会在首次调用 play()、record()、playrec() 或 start() 时隐式初始化。请勿调用 setup(),否则会报错。
如果设置了 PlayerFcn,首次调用流式传输方法时会反复调用它,以便在设备打开前预缓冲至少 8192 个样本(或 PlayerMinSamples 指定的数量,取较大者)。
常见模式
模式 1:简单的阻塞测量(扫频 + IR)
as = audiostreamer(Mode="full-duplex", SampleRate=48000, ...
PlayerChannels=1, RecorderChannels=1);
x = sweeptone(2, 1, 48000);
y = playrec(as, x, size(x, 1)); % blocking: returns recorded audio
underruns = getUnderrunCount(as);
ir = impzest(x, y);
release(as);
模式 2:非阻塞播放 + 录音,并使用 waitfor
as = audiostreamer(Mode="full-duplex", SampleRate=48000);
x = sweeptone(3, 2, 48000);
playrec(as, x); % non-blocking (no output arg)
waitfor(as); % block until done
y = read(as); % retrieve recorded data
release(as);
模式 3:预缓冲播放(write + start)— R2026a+
如果需要精确控制播放开始时间(例如,同步启动全双工),请使用 write+start。对于简单播放,play(as, signal) 效果相同——它会将数据排队并自动启动。
as = audiostreamer(Mode="player", SampleRate=48000);
write(as, signal); % queue without starting
start(as); % begin playback
waitfor(as); % wait for completion
release(as);
模式 4:由回调驱动的流式播放器
as = audiostreamer(Mode="player", SampleRate=48000, DeviceBufferSize=1024);
gen = dsp.ColoredNoise("pink", NumChannels=2, SamplesPerFrame=1024);
as.PlayerFcn = @(obj, ~) play(obj, gen());
as.PlayerMinSamples = 4096;
play(as); % or start(as) [R2026a+] — begins callback loop
% ... later ...
stop(as);
release(as);
模式 5:由回调驱动的电平计量(录音器)
as = audiostreamer(Mode="recorder", SampleRate=48000);
as.RecorderFcn = @(obj, ~) updateMeter(read(obj));
as.RecorderMinSamples = 1024;
start(as); % or record(as) before R2026a
% ... meter updates in background ...
stop(as);
release(as);
模式 6:逐帧处理循环(全双工)
这是替代旧版 audioDeviceReader/audioDeviceWriter 循环最直接的方式。在循环前调用 start(as),确保 read 有可用样本。
as = audiostreamer(Mode="full-duplex", SampleRate=48000, RecorderChannels=1:2);
start(as);
for iter = 1:numIterations
in = read(as, frameLength); % blocks until frameLength samples available
out = process(myPlugin, in);
write(as, out); % blocks until buffer has room
end
nUnderruns = getUnderrunCount(as); % total underruns since last call (resets counter)
release(as);
在 R2026a 之前,请使用 record(as) + play(as, out),而非 start/write。
仅使用播放器时(例如,文件输入 → 设备输出),调用 play(as, out) 即可,无需调用 start——play 会将数据排队并自动启动。
模式 7:使用回调进行重复测量(全双工)
as = audiostreamer(Mode="full-duplex", SampleRate=48000, PlayerChannels=1, RecorderChannels=1);
x = sweeptone(2, 1, 48000);
as.RecorderMinSamples = size(x, 1);
as.RecorderFcn = @(obj, ~) processMeasurement(obj, x);
as.PlayerFcn = @(obj, ~) write(obj, x); % or play(obj, x) before R2026a
as.PlayerMinSamples = size(x, 1);
as.ConstantLatency = "dropPlayer"; % keep in sync for impzest
playrec(as); % starts callback-driven measurement loop
% ... runs continuously ...
stop(as);
release(as);
模式 8:使用基于计时器的 GUI 更新的应用
as = audiostreamer(Mode="player", SampleRate=fs, DeviceBufferSize=1024);
as.PlayerFcn = @(obj, ~) play(obj, getNextFrame());
as.PlayerMinSamples = 20 * 1024;
as.PlayerUnderrunFcn = @(~, ev) fprintf("Dropped %d samples\n", ev.SamplesUnderrun);
figTimer = timer(ExecutionMode="fixedRate", Period=0.05, ...
TimerFcn=@(~,~) updatePlot(as));
play(as); % starts callback loop
start(figTimer); % starts GUI updates
% ...
stop(as);
release(as);
stop(figTimer);
delete(figTimer);
在计时器回调中,在执行耗时的 GUI 操作前检查缓冲区状态:
function updatePlot(as)
if as.NumPlayerSamples < 0.5 * as.PlayerMinSamples
return % skip GUI update to prevent dropout
end
% ... update plots ...
if as.NumPlayerSamples > 0.9 * as.PlayerMinSamples
drawnow("limitrate");
end
end
模式 9:使用 write/start 控制全双工 — R2026a+
as = audiostreamer(Mode="full-duplex", SampleRate=48000);
write(as, excitation); % queue output
start(as, SamplesToRecord=size(excitation,1)); % start both
waitfor(as, "both");
y = read(as);
release(as);
拆解最佳实践
release(as) 已足够——它会隐式停止流传输、刷新缓冲区并关闭设备。无需先调用 stop。不过,release 会丢弃尚未播放的样本——如果必须等播放完成,请先调用 waitfor(as)。
waitfor(as); % ensure all queued audio finishes playing
release(as);
在应用中,请用 try-catch 包装并将引用设为 nil:
try
release(as);
catch
end
as = [];
析构函数会自动调用 release(),但在应用中,最好显式清理,以避免设备锁死。在 PlayerCompletedFcn 中调用 release 是安全的,不会导致死锁。
注意: 即使释放后,isvalid(as) 仍会返回 true——不能用它来检测 audiostreamer 是否已释放。要跟踪释放状态,请将对象引用设为 nil,并使用 isempty 检查。
ConstantLatency 模式(全双工)
| 值 | 行为 | 适用场景 |
|---|---|---|
"off" | 发生丢帧后插入静音帧(延迟增加) | 常规用途 |
"dropPlayer" | 丢弃迟到的输出帧;延迟保持恒定 | 使用 impzest 的测量(基于扫频) |
"dropRecorder" | 丢弃输入帧;延迟保持恒定 | 自适应滤波器(与 impzest 不兼容) |
错误情况
| 错误 ID | 原因 |
|---|---|
audio:device:methodRequiresModes | 调用的方法对当前 Mode 无效(例如,在播放器模式下调用 record())。如果需要同时使用播放和录制方法,请将 Mode 设为 "full-duplex"。 |
audio:device:invalidChannelMap | 通道索引超出设备最大值。请检查 MaxPlayerChannels 或 MaxRecorderChannels,并调整映射。 |
audio:device:callbackNargin | 回调未接受恰好 2 个参数。请使用 @(obj, ~) 或 @(obj, event) 签名。 |
audio:device:playrecRecorderFcnConflict | 设置了 RecorderFcn 时调用 playrec 并提供输出参数——回调通过 read() 消费样本,导致返回值没有可用数据。在阻塞式 playrec 前,请清除 RecorderFcn。 |
audio:device:startModePlayerNotValid | 在仅录制模式下调用 start(Mode="player") |
audio:device:startModeRecorderNotValid | 在仅播放模式下调用 start(Mode="recorder") |
MATLAB:validators:mustBeFinite | 音频数据包含 NaN 或 Inf |
MATLAB:validators:mustBeReal | 音频数据为复数 |
audiostreamer 与旧版音频 API 的对比
只要 Audio Toolbox 可用,强烈建议使用 audiostreamer 进行所有音频设备 I/O。未安装 Audio Toolbox 或某些特殊情况下,旧版替代方案可能适合作为备用方案。
| 旧版 API | 局限性 | audiostreamer 对应方案 |
|---|---|---|
audiodevinfo | 不支持 ASIO;设备列表不完整 | audiostreamer.getAudioDevices()、audiostreamer.getPlayerNames() 等 |
audioplayer / audiorecorder | 不支持 ASIO/WASAPI 独占模式;驱动程序模型有限;没有回调 | 使用播放器/录制器/全双工模式的 audiostreamer |
sound / soundsc | 底层会创建 audioplayer;并发调用会重叠(不要排队) | 使用 play() 顺序播放的 audiostreamer |
audioDeviceWriter / audioDeviceReader | 对象分离;没有回调;没有预缓冲;只能逐帧循环 | 单个 audiostreamer 对象,支持阻塞/非阻塞模式 |
audioPlayerRecorder | 全双工能力有限;没有传输控制;无法测量延迟 | playrec、measureLoopbackLatency、start/stop/pause/resume |
可以调用 audiodevreset——它会重置音频子系统,无论使用哪种 API,都有助于从设备错误中恢复。
适合使用 sound/soundsc 的情况: 仅限单次独立播放,且不需要编排播放顺序。如果需要连续播放两个片段(例如进行前后对比),请使用 audiostreamer——它的 play() 调用会自动排队。
迁移注意事项(audioDeviceReader/Writer → audiostreamer)
| 旧版 | audiostreamer | 注意事项 |
|---|---|---|
audioDeviceReader with NumChannels=2 | RecorderChannels=1:2 | audiostreamer 默认录制 1 个声道。要录制立体声或多声道,必须显式设置 RecorderChannels。 |
audioDeviceWriter returns underrun count per frame | getUnderrunCount(as) after loop | play() 没有返回值。需要获取总数时,请调用 getUnderrunCount——每次调用都会重置计数器。 |
audioDeviceReader returns overrun count per frame | No equivalent needed | audiostreamer 会在内部缓冲所有录制的样本,因此录音器不会发生溢出。 |
Device='Default' | Omit Player/Recorder | 没有 "Default" 字符串——省略该属性会为当前驱动选择系统默认设备。 |
[data, nOverrun] = deviceReader() | record(as) then data = read(as, N) | 必须在循环前调用 record(as)(或 start(as) [R2026a+]),否则 read 会因等待样本而无限阻塞。 |
| 两个独立对象分别用于读取和写入 | audiostreamer(Mode="full-duplex") 单个对象 | 一个对象可处理两个方向。如果设备需要不同的驱动,或同时打开时会发生冲突,请使用两个独立对象。 |
诊断
要调试流式处理问题,请启用诊断跟踪:
as = audiostreamer(Mode="full-duplex", SampleRate=44100);
as.TraceEnabled = true; % logs internal timing and buffer state
版权所有 2026 The MathWorks, Inc.