How to validate a core audio audio unit
Creating an audio unit for macOS or iOS is hard work and much care is needed to ensure the audio unit will behave the correct way inside a native app. Even more care is required so your audio unit will behave correctly in other software outside your control.
We really need to ensure the audio unit implements all of the standards correctly; ensure we have no memory leaks and ensure the plugin performs under high load.
Fortunately Apple have gifted with such a console command! auval
In your favourite terminal run auval -a
to get started. You should see all of the audio units installed on your system
with any problems encountered. You will have many more, this is a shortened version:
auval -a
aufx dely appl - Apple: AUDelay
aufx dist appl - Apple: AUDistortion
aumu dls appl - Apple: DLSMusicDevice
aumu msyn appl - Apple: AUMIDISynth
aumx 3dem appl - Apple: AUSpatialMixer
aumx 3dmx appl - Apple: AUMixer3D
aumx mcmx appl - Apple: AUMultiChannelMixer
aufc conv appl - Apple: AUConverter
aufc defr appl - Apple: AUDeferredRenderer
auou ahal appl - Apple: AudioDeviceOutput
auou def appl - Apple: DefaultOutputUnit
augn afpl appl - Apple: AUAudioFilePlayer
augn nrcv appl - Apple: AUNetReceive
auol tmpt appl - Apple: AUTimePitch
auol vari appl - Apple: AUVarispeed
If you are familiar with core audio you may recognise the first 3 columns as type, subtype and manufacturer.
Tell me more
After looking at all the plugins in your system you can get a full detailed validation report
using the -v
option with the identifier codes (type, subtype and manufacturer). We should also use the -strict
option to ensure the tool does not pull any punches during the validation. There is a lot of output
that can be overwhelming, the important part is the last line (eg did it pass?):
auval -strict -v augn nrcv appl
AU Validation Tool
Version: 1.10.0
Copyright 2003-2019, Apple Inc. All Rights Reserved.
Specify -h (-help) for command options
--------------------------------------------------
VALIDATING AUDIO UNIT: 'augn' - 'nrcv' - 'appl'
--------------------------------------------------
Manufacturer String: Apple
AudioUnit Name: AUNetReceive
Component Version: 1.6.0 (0x10600)
* * PASS
--------------------------------------------------
TESTING OPEN TIMES:
COLD:
Time to open AudioUnit: 7.588 ms
WARM:
Time to open AudioUnit: 0.072 ms
This AudioUnit is a version 2 implementation.
FIRST TIME:
Time for initialization: 0.935 ms
* * PASS
--------------------------------------------------
VERIFYING DEFAULT SCOPE FORMATS:
Input Scope Bus Configuration:
Default Bus Count:0
Output Scope Bus Configuration:
Default Bus Count:1
Default Format: AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Has Channel Layouts: 0x0
* * PASS
--------------------------------------------------
VERIFYING REQUIRED PROPERTIES:
* * PASS
--------------------------------------------------
VERIFYING RECOMMENDED PROPERTIES:
* * PASS
--------------------------------------------------
VERIFYING OPTIONAL PROPERTIES:
VERIFYING PROPERTY Latency
PASS
* * PASS
--------------------------------------------------
VERIFYING SPECIAL PROPERTIES:
VERIFYING CUSTOM UI
Cocoa Views Available: 1
AUNetReceiveViewFactory
PASS
VERIFYING CLASS INFO
PASS
TESTING HOST CALLBACKS
PASS
* * PASS
--------------------------------------------------
PUBLISHED PARAMETER INFO:
# # # 1 Global Scope Parameters:
Parameter ID:0
Name: Connected Indicator
Parameter Type: Indexed
Values: Minimum = 0.000000, Default = 0.000000, Maximum = 4.000000
Flags: Readable,
-parameter PASS
Testing that parameters retain value across reset and initialization
PASS
* * PASS
--------------------------------------------------
FORMAT TESTS:
Reported Channel Capabilities (explicit):
[0, -1]
No Input, Output Chans:
0-1 0-2 0-4 0-5 0-6 0-7 0-8
X X X X X X X
# # AudioChannelLayouts (1), Output Scope:
ChannelLayout is Writable: T
The Unit publishes the following Channel Layouts:
0x0 (Use_Channel_Descriptions)
Is Audio Channel Layout Available:
Mono Stereo Binau. AU_4 Ambi. AU_5 AU_5_0 AU_6 AU_6_0 AU_7_0 AU_7_0F AU_8 AU_5_1 AU_6_1 AU_7_1 AU_7_1F
X X X X X X X X X X X X X X X X
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x650002, New Format Tag = 0x650002, Successsful
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x650002, New Format Tag = 0x6A0002, Successsful
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x6C0004, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x6B0004, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x6D0005, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x760005, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x6E0006, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x8B0006, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x8C0007, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x940007, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x6F0008, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x790006, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x7D0007, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x800008, Success - did not reset format with mis-matched layout
Current Format:AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Current Format Tag = 0x6A0002, New Format Tag = 0x7E0008, Success - did not reset format with mis-matched layout
* * PASS
--------------------------------------------------
RENDER TESTS:
Output Format: AudioStreamBasicDescription: 2 ch, 44100 Hz, Float32, deinterleaved
Render Test at 512 frames
Slicing Render Test at 64 frames
PASS
Render Test at 64 frames, sample rate: 22050 Hz
Render Test at 137 frames, sample rate: 96000 Hz
Render Test at 4096 frames, sample rate: 48000 Hz
Render Test at 4096 frames, sample rate: 192000 Hz
Render Test at 4096 frames, sample rate: 11025 Hz
Render Test at 512 frames, sample rate: 44100 Hz
PASS
1 Channel Test:
Render Test at 512 frames
PASS
Bad Max Frames - Render should fail
PASS
Test MIDI
PASS
* * PASS
--------------------------------------------------
AU VALIDATION SUCCEEDED.
--------------------------------------------------
Time to get stressed
We also have options to put our plugin through its paces to ensure it will be as stable as it can be. There are a few combinations we can use:
-r <number of repeats>
: This will repeat the test multiple times, and all iterations must pass for a successful output. For example-r 10
to repeat 10 times.-stress <seconds>
: The help pages tell us this means "Run additional multi-thread stress test for N simulated seconds of audio I/O. Good for catching race condition bugs". Note it is "simulated seconds" so if you set it for 600 seconds the command will not take 10 minutes to complete. Instead the command is pushing 600 seconds of audio through the plugin at high speed.
Check for leaks
The stress options will only fail if an edge case is triggered due to the extra load. The plugin could be leaking memory but a stress test will not find it unless it is a really bad leak.
We can check for more subtle leaks using the -w
option, ideally in combination with the stress options to run the
plugin code as much as possible. The -w
option causes the auval
command to wait when it is finished, so you can
open the leaks
command in a different terminal session to see if the testing session leaked any memory, eg
leaks auval
Help is at hand
Finally, all of these details and more can be seen with the command help auval -h
One more thing....
There is another tool to confirm that audio extensions have been registered with the system. This will tell you the name of the extension and the location.
pluginkit -mv