Generated banner for Matlab Play Record Audio
Generated logo for Matlab Play Record Audio

Matlab Play Record Audio

MathWorksOfficialCreated by MathWorks

  • Skill
  • Tool integration
  • Science and research
  • BSD-2-Clause
  • No issues found

From the author

Reference for MATLAB audiostreamer (Audio Toolbox R2025a+). Without this skill, agents consistently default to legacy audioDeviceWriter/audioDeviceReader or base MATLAB sound(), producing less capable code. Use when writing code for audio playback, recording, full-duplex device I/O, real-time audio measurements, or audio I/O processing with callbacks. Also use when debugging audiostreamer errors, dropouts, or latency issues, or migrating from audioDeviceReader, audioDeviceWriter, audioPlayerRecorder, or audioplayer/audiorecorder.
— the description by MathWorks

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The audiostreamer skill provides a comprehensive reference for the unified MATLAB audio device I/O interface introduced in Audio Toolbox R2025a. It replaces legacy objects like audioDeviceWriter, audioDeviceReader, and audioPlayerRecorder, offering a single object for player, recorder, or full-duplex modes. The skill covers construction, property configuration, callback management, transport control, and diagnostic methods, ensuring users can implement audio streaming, measurement, and processing workflows effectively.

What it does

  • Provides configuration for audio playback, recording, and full-duplex I/O.
  • Details callback mechanisms for buffer management and event handling.
  • Explains transport control methods including start, stop, pause, and resume.
  • Lists static methods for enumerating available audio drivers and devices.
  • Outlines diagnostic tools for monitoring stream time and underrun counts.
  • Documents migration patterns from legacy MATLAB audio APIs.

When to use it

  • When implementing audio playback or recording in MATLAB R2025a or later.
  • When performing full-duplex audio I/O for measurements or loopback tests.
  • When building callback-driven audio processing loops.
  • When selecting specific audio drivers like ASIO or WASAPI.
  • When migrating existing code from legacy audioDeviceReader or audioDeviceWriter.

Advantages

  • Unified interface for all audio device I/O modes.
  • Supports callback-based streaming for responsive applications.
  • Enables repeatable latency for measurement workflows.
  • Provides built-in diagnostic and device enumeration capabilities.
  • Allows for explicit control over device buffers and channel mapping.

Usage examples

“How do I initialize a full-duplex audiostreamer for 48kHz recording and playback?”
Use as = audiostreamer(Mode='full-duplex', SampleRate=48000) to initialize the object for simultaneous I/O.
“How can I retrieve a list of available audio devices in MATLAB?”
Call audiostreamer.getAudioDevices() to return a struct array containing device names, drivers, and channel capabilities.
“What is the correct way to ensure playback finishes before releasing the device?”
Call waitfor(as) to block until the output buffer is empty, followed by release(as) to close the device.
“How do I handle audio data in a loop using audiostreamer?”
Call start(as) before the loop, then use read(as, frameLength) to retrieve input samples and write(as, output) to send processed data to the output buffer.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/matlab/matlab-play-record-audio/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip matlab-play-record-audio.zip -d .agents/skills

Documentation by MathWorks

audiostreamer — MATLAB Audio Device I/O (R2025a+)

audiostreamer is the unified replacement for audioDeviceWriter, audioDeviceReader, and audioPlayerRecorder. It provides player-only, recorder-only, or full-duplex modes with callbacks, pre-buffering, transport control, and measurement helpers.

Version requirements: audiostreamer requires Audio Toolbox R2025a or later. The start and write methods were added in R2026a.

When to Use

  • Playing audio through a sound card or USB audio device

  • Recording audio from a microphone or audio interface

  • Full-duplex playback + recording (e.g., acoustic measurements, loopback tests)

  • Listing or selecting audio devices and drivers

  • Any workflow that involves audio hardware I/O in MATLAB

When NOT to Use

  • Playing a single isolated sound — sound or soundsc is fine for one-shot playback of a short clip with no sequencing. For sequential playback (e.g., before/after comparison), use audiostreamer — its play() calls queue automatically, whereas overlapping sound calls play simultaneously.

  • Code generation (codegen) — audiostreamer does not yet support codegen; use legacy APIs if targeting codegen

  • Simulink models — Simulink still uses the existing audio I/O blocks, not audiostreamer

  • Audio Toolbox not available — fall back to sound/soundsc, audioplayer/audiorecorder, or audioDeviceWriter (DSP System Toolbox) if the user lacks Audio Toolbox

  • File I/O only — reading/writing audio files without device playback or recording uses audioread/audiowrite, not this skill

  • DAQ hardware — National Instruments or similar data acquisition devices use DAQ Toolbox and the daq object

  • MIDI-only devices — MIDI control uses mididevice/midicontrols, not audiostreamer

Construction

Use Name-Value pairs for Mode and SampleRate (positional shorthand exists but does not support tab-completion):

The default Mode is "player". You MUST set Mode explicitly if recording — either Mode="recorder" or Mode="full-duplex". Mode is not inferred from other properties like Recorder or RecorderChannels.

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])

Properties

Device Configuration (set BEFORE streaming starts)
PropertyTypeDefaultNotes
Mode"player" / "recorder" / "full-duplex""player"Set at construction or via property
Driver"DirectSound" / "ASIO" / "WASAPI" (Win); "CoreAudio" (Mac); "ALSA" (Linux)OS defaultOnly set on Windows (Mac/Linux have one driver each). Setting at construction selects the default device for that driver.
PlayerstringSystem default for driverOutput device name. Omit to use the default device for the selected driver.
RecorderstringSystem default for driverInput device name. Omit to use the default device for the selected driver.
SampleRatepositive scalar44100Hz
DeviceBufferSizepositive int or "auto""auto"Fixed for ASIO (use asiosettings).
DeviceBitFormat"single" / "int24" / "int16""int24"int16 on ASIO silently uses int24
PlayerChannelsrow vector or "auto""auto"1-based mapping. "auto" upmixes mono→stereo; for N≥2 channels, opens N channels on the device
RecorderChannelsrow vector11-based mapping. Records 1 channel by default — set e.g. 1:2 for stereo
ExclusiveModeon/off"on"WASAPI only — disables OS mixing/resampling
ConstantLatency"off" / "dropPlayer" / "dropRecorder""off"Full-duplex dropout handling

IMPORTANT: Mode, SampleRate, Driver, DeviceBufferSize, DeviceBitFormat, ExclusiveMode, ConstantLatency, PlayerChannels, and RecorderChannels lock once streaming starts. Call release(as) before changing any of these properties to avoid an automatic release with a warning.

Callback Properties
PropertySignatureTrigger
PlayerFcn@(obj, event)Player buffer drops below PlayerMinSamples
PlayerMinSamplespositive int (default 16384)Threshold for PlayerFcn trigger
RecorderFcn@(obj, event)Recorder buffer exceeds RecorderMinSamples
RecorderMinSamplespositive int (default 1024)Threshold for RecorderFcn trigger
PlayerCompletedFcn@(obj, event)Output queue empties
RecorderCompletedFcn@(obj, event)Fixed-length recording finishes
PlayerUnderrunFcn@(obj, event)Player underrun occurs

ALL callbacks MUST accept exactly 2 arguments. First arg = the audiostreamer object. Second arg = event struct with .Type field. Use @(obj, ~) if you don't need the event.

Event struct fields by type:

  • PlayerFcn: event.Type = "Player", event.NumPlayerSamples

  • RecorderFcn: event.Type = "Recorder", event.NumRecorderSamples

  • PlayerCompletedFcn: event.Type = "PlayerCompleted", event.StreamTime

  • RecorderCompletedFcn: event.Type = "RecorderCompleted", event.StreamTime

  • PlayerUnderrunFcn: event.Type = "PlayerUnderrun", event.SamplesUnderrun

Read-Only Status
PropertyDescription
NumPlayerSamplesSamples currently queued in output buffer
NumRecorderSamplesSamples available to read() without blocking
MaxPlayerChannelsMax output channels on selected device
MaxRecorderChannelsMax input channels on selected device

Methods

Playback
MethodDescription
play(obj, x)Queue x and play. Blocks until output buffer <= PlayerMinSamples (up to PlayerMinSamples samples remain unplayed when it returns). Call waitfor(as) after the last play to ensure complete playback before release.
play(obj, x, "non-blocking")Queue x and return immediately regardless of buffer level.
play(obj)Start PlayerFcn callback loop (no data argument).
write(obj, x)[R2026a+] Queue x to output buffer WITHOUT starting playback. Use with start().
write(obj, x, "non-blocking")[R2026a+] Queue x and return immediately regardless of buffer level.
Recording
MethodDescription
record(obj)Start recording indefinitely. Warns if unread samples remain in the buffer. To avoid: stop(as) (or stop(as, "recorder") in full-duplex), then read(as) to flush. Not needed if samples were already consumed by a callback or read.
record(obj, numSamples)Record exactly numSamples then stop. Same unread-samples warning applies.
read(obj)Return all available recorded samples immediately (non-blocking). Returns empty if none available.
read(obj, numSamples)Blocks until numSamples available, then returns them.
Full-Duplex
MethodDescription
playrec(obj, x)Play x and record simultaneously. Non-blocking — recording continues in the background; retrieve data with read.
playrec(obj, x, numSamples)Play x and record numSamples. Blocking — returns recorded matrix.
playrec(obj)Start callback-driven full-duplex (requires RecorderFcn and/or PlayerFcn).

playrec pauses both player and recorder, queues audio, then resumes both simultaneously for repeatable latency. This is critical for measurements with impzest.

Transport Control
MethodDescription
start(obj)[R2026a+] Start streaming in current mode.
start(obj, Mode="player")[R2026a+] Start only player (full-duplex).
start(obj, Mode="recorder", SamplesToRecord=N)[R2026a+] Start recorder with fixed count.
stop(obj)Stop all streaming. Preserves unread input samples. Resets underrun count (as does getUnderrunCount).
stop(obj, "player"/"recorder"/"both")Stop specific side.
pause(obj) / pause(obj, "player"/"recorder"/"both")Pause with state preservation.
resume(obj) / resume(obj, "player"/"recorder"/"both")Resume from pause.
waitfor(obj) / waitfor(obj, "player"/"recorder"/"both")Block until complete.
release(obj)Stop, flush, close device, tear down. Deletes unread samples.
Query / Diagnostics
MethodDescription
isPlaying(obj)Returns OnOffSwitchState
isRecording(obj)Returns OnOffSwitchState
isPlayerPaused(obj)Returns OnOffSwitchState
isRecorderPaused(obj)Returns OnOffSwitchState
getUnderrunCount(obj)Underrun sample count since last call. Resets counter (as does stop).
getStreamTime(obj)Elapsed stream time in seconds.
getStreamTime(obj, "reset")Reset stream timer.
measureLoopbackLatency(obj)Full-duplex only, single channel. Returns delay in samples.
Static Device Enumeration
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)

Note: getAudioDevices() returns int32 for MaxRecorderChannels and MaxPlayerChannels. Cast to double() before using these values in UI components (e.g., uispinner Limits) or arithmetic that expects double.

CRITICAL: There is NO setup() Method

The audiostreamer does NOT have a public setup() method. Device initialization happens implicitly on the first play(), record(), playrec(), or start() call. Do NOT call setup() — it will error.

If PlayerFcn is set, the first streaming call invokes it repeatedly to pre-buffer at least 8192 samples (or PlayerMinSamples, whichever is greater) before the device opens.

Common Patterns

Pattern 1: Simple Blocking Measurement (Sweep + 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);
Pattern 2: Non-Blocking Play + Record with 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);
Pattern 3: Pre-Buffered Playback (write + start) — R2026a+

Use write+start when you need to control exactly when playback begins (e.g., synchronized full-duplex start). For simple playback, play(as, signal) achieves the same result — it queues and starts automatically.

as = audiostreamer(Mode="player", SampleRate=48000);
write(as, signal);       % queue without starting
start(as);               % begin playback
waitfor(as);             % wait for completion
release(as);
Pattern 4: Callback-Driven Streaming Player
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);
Pattern 5: Callback-Driven Level Metering (Recorder)
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);
Pattern 6: Frame-at-a-Time Processing Loop (Full-Duplex)

The most direct replacement for legacy audioDeviceReader/audioDeviceWriter loops. Call start(as) before the loop so that read has samples available.

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);

Before R2026a, use record(as) + play(as, out) instead of start/write.

For player-only (e.g., file input → device output), use play(as, out) with no start needed — play queues and starts automatically.

Pattern 7: Repeated Measurements with Callbacks (Full-Duplex)
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);
Pattern 8: App with Timer-Based GUI Updates
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);

In the timer callback, check buffer health before expensive GUI operations:

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
Pattern 9: Full-Duplex with write/start for Control — 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);

Teardown Best Practice

release(as) is sufficient — it implicitly stops streaming, flushes buffers, and closes the device. No need to call stop first. However, release discards any unplayed samples — call waitfor(as) first if playback must complete.

waitfor(as);   % ensure all queued audio finishes playing
release(as);

In apps, wrap in try-catch and nil the reference:

try
    release(as);
catch
end
as = [];

The destructor calls release() automatically, but explicit cleanup is preferred in apps to avoid device lock-up. Calling release from within PlayerCompletedFcn is safe and does not deadlock.

Note: isvalid(as) returns true even after release — it cannot be used to detect a released audiostreamer. To track released state, nil the object reference and check with isempty.

ConstantLatency Modes (Full-Duplex)

ValueBehaviorUse For
"off"After dropout, inserts silence frame (latency increases)General use
"dropPlayer"Late output frames dropped; latency stays constantMeasurements with impzest (sweep-based)
"dropRecorder"Input frames dropped; latency constantAdaptive filters (NOT compatible with impzest)

Error Conditions

Error IDCause
audio:device:methodRequiresModesCalling method invalid for current Mode (e.g., record() in player mode). Set Mode to "full-duplex" if you need both playback and recording methods.
audio:device:invalidChannelMapChannel indices exceed device max. Check MaxPlayerChannels or MaxRecorderChannels and adjust mapping.
audio:device:callbackNarginCallback doesn't accept exactly 2 arguments. Use @(obj, ~) or @(obj, event) signature.
audio:device:playrecRecorderFcnConflictplayrec called with output argument while RecorderFcn is set — callback consumes samples via read(), leaving nothing for the return value. Clear RecorderFcn before blocking playrec.
audio:device:startModePlayerNotValidstart(Mode="player") in recorder-only mode
audio:device:startModeRecorderNotValidstart(Mode="recorder") in player-only mode
MATLAB:validators:mustBeFiniteAudio data contains NaN or Inf
MATLAB:validators:mustBeRealAudio data is complex

audiostreamer vs. Legacy Audio APIs

audiostreamer is strongly preferred for all audio device I/O when Audio Toolbox is available. Legacy alternatives may be useful as fallbacks when Audio Toolbox is not installed or in edge cases.

Legacy APILimitationaudiostreamer Equivalent
audiodevinfoDoes not support ASIO; incomplete device listaudiostreamer.getAudioDevices(), audiostreamer.getPlayerNames(), etc.
audioplayer / audiorecorderNo ASIO/WASAPI exclusive; limited driver model; no callbacksaudiostreamer in player/recorder/full-duplex mode
sound / soundscCreates an audioplayer under the hood; concurrent calls overlap (do NOT queue)audiostreamer with play() for sequential playback
audioDeviceWriter / audioDeviceReaderSeparate objects; no callbacks; no pre-buffering; frame-at-a-time loops onlySingle audiostreamer object with blocking/non-blocking modes
audioPlayerRecorderLimited full-duplex; no transport control; no latency measurementplayrec, measureLoopbackLatency, start/stop/pause/resume

audiodevreset is fine to call — it resets the audio subsystem and can help recover from device errors regardless of which API you use.

When sound/soundsc is acceptable: Only for a single isolated playback with no sequencing. If you need to play two clips back-to-back (e.g., before/after comparison), use audiostreamer — its play() calls queue automatically.

Migration Pitfalls (audioDeviceReader/Writer → audiostreamer)
LegacyaudiostreamerGotcha
audioDeviceReader with NumChannels=2RecorderChannels=1:2audiostreamer records 1 channel by default. You must set RecorderChannels explicitly for stereo/multichannel.
audioDeviceWriter returns underrun count per framegetUnderrunCount(as) after loopplay() has no return value. Call getUnderrunCount when you need the total — it resets the counter each call.
audioDeviceReader returns overrun count per frameNo equivalent neededaudiostreamer buffers all recorded samples internally — recorder cannot overrun.
Device='Default'Omit Player/RecorderNo "Default" string — omitting the property selects the system default for the current driver.
[data, nOverrun] = deviceReader()record(as) then data = read(as, N)Must call record(as) (or start(as) [R2026a+]) before the loop — otherwise read blocks forever waiting for samples.
Two separate objects for reader+writerSingle audiostreamer(Mode="full-duplex")One object handles both directions. Use two separate objects if devices require different drivers or conflict when opened together.

Diagnostics

For debugging streaming issues, enable the diagnostic trace:

as = audiostreamer(Mode="full-duplex", SampleRate=44100);
as.TraceEnabled = true;   % logs internal timing and buffer state

Copyright 2026 The MathWorks, Inc.


Files

manifest.yaml

# Copyright 2026 The MathWorks, Inc.
schema-version: 1
license: https://www.mathworks.com/content/dam/mathworks/license/pmrl/license.md
scope: cross-product
version: "1.0"
human-description: Play and record audio in MATLAB using audiostreamer.
matlab-release: ">=R2025a"
required-tools:
  - evaluate_matlab_code
  - check_matlab_code
required-skills: []
required-products:
  - Audio Toolbox
  - DSP System Toolbox
toolkit: matlab-agentic-toolkit

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
MathWorks
Publisher
MathWorks (Official)
Source
matlab/matlab-agentic-toolkit · skills-catalog/signal-processing/matlab-play-record-audio · commit 2a7f215
Licence
BSD 2-Clause License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE.md)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by MathWorks.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-play-record-audio.zip