How to validate a core audio audio unit

17th Jul, 2022 | coreaudio

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