AWECoreOS 8.A.1 User's Guide
AWE Core OS User Guide

Table of Contents


This User Guide is designed to give an overview on the usage and functionality of the AWE Core OS™ product.

AWE Core OS is a hardware-independent, reconfigurable audio-processing engine that includes over 400 audio-processing modules. From mixers and filters to compressors and FFTs, these modules can be easily combined to create complex signal processing flows. The AWE Core OS engine operates by passing audio through a user-defined sequence of these modules, called a layout, as directed by configuration data at run-time.

AWE Core vs AWE Core OS

While the AWE Core™ product is meant to be a portable library that targets bare-metal applications, AWE Core OS targets applications using a rich OS, such as Linux or Android. AWE Core OS extends the functionality of the AWE Core by taking advantage of features common to these Operating Systems, such as File I/O, TCP/IP Sockets, and multi-threading. Using native components of AWE Core OS, users can easily load layouts from AWBs, record input and output audio streams, process and log TCP/IP tuning command packets, and run complex, multi-sublayout signal processing flows across multiple cores.

Terms and Definitions

Term Definition
APIApplication Programming Interface
AWBAudio Weaver configuration data binary file
AWD Audio Weaver configuration data design file
AWE Audio Weaver
AWE OS InstanceThe main AWE Core OS object
AWS Audio Weaver configuration data script file
Clock Divider Property of multi-rate layouts
Layout Audio Weaver signal processing flow
Pump Process audio using a loaded layout
Tuning InterfaceThe interface by which AWE tuning commands/replies are transferred
Sub-Layout Independently processed section of a layout with a unique clock divider

Additional Documentation

This document will describe how to use various components of AWE Core OS in an audio processing application. For related documentation, see:

API Documentation: AWECoreOS API Doc.

Brief view of the API: See 'AWECoreOS_cheatsheet.pdf' in this package.

Details on underlying concepts and operation: Theory Of Operation

Help with ALSA Devices: Alsa Devices

Tuning protocol details: Tuning Protocol Doc.

Overview of Integration Steps

Here are the basic steps to include AWE Core OS in an application.

  1. Include headers and link libraries in build projects
  2. Define/allocate required variables
  3. Configure and initialize the AWE Core OS instance
  4. Setup a tuning interface
  5. Setup realtime audio
  6. Setup a control interface (optional based on product intent)
  7. Verify proper scheduling/priority.

Include Headers and Link Libraries

Required Header Files

Required Libraries

Update application build project to link the following libraries:

Helper Code / Optional

Initializing the AWE OS Instance

Declaring the Required Variables

A number of variables must be defined before configuring/initializing the AWE Instance.

Configuring the AWE OS Instance

AWE Core OS provides a function aweOS_getParamDefaults to fill a configuration parameter structure with default values. See AWEOSConfigParameters for details on the default values. It is recommended to always call aweOS_getParamDefaults in an application to get the default values, and then overwrite any of the defaults with user parameters as needed. The remainder of this section describes the individual configuration parameters in more detail.

Optionally overwrite any configuration parameters with values as appropriate for application

If not planning on using aweOS_tuningSocketOpen, allocate and assign packet buffer(s) to be used by user created tuning interface.

Initializing the AWE OS Instance

Once the instance parameters are configured correctly, initialize the AWE OS Instance by calling aweOS_init. If aweOS_init is called before the configuration parameter structure is fully configured, the initialization will fail. The module table and table size must also be provided to the initialization function. Note that a pointer to the AWE OS Instance pointer (AKA Double Pointer) must be the first argument.

int ret = aweOS_init(&g_AWEOSInstance, &configParams, moduleDescriptorTable, moduleDescriptorTableSize);

Setting up a Tuning Interface

Once the AWEOSInstance is initialized, the next step is to enable a tuning interface. One of the most important components of an AWE Core OS application, a tuning interface provides a communication channel between the AWE OS Instance and an application like AWE Server running on the host PC. This communication channel is essential as it provides key audio tuning and debugging capabilities. For example, tuning commands can instantiate on the target a layout generated in AWE Designer, or set and query the values of module parameters in real-time. Most AWE Core OS applications will use the built-in aweOS_tuningSocketOpen function to open a TCP/IP socket that can be used to communicate with AWE Server.

    INT32 interfaceRet = aweOS_tuningSocketOpen(&g_AWEOSInstance, PORTNO, 1);
    if (interfaceRet == E_SUCCESS)
        printf("Opened TCP tuning interface on port %d: Waiting for AWE Server Connection from PC... \n", PORTNO);

See Tuning Protocol Doc for more details on tuning commands and creating a custom tuning interface. Also see aweOS_tuningSocketClose and aweOS_tuningLoggingEnable for additional control functions for the built-in tuning interface.

Real-time Audio

RT Audio Introduction

The next step is to integrate real-time audio. AWE Core OS aside, real-time audio can be a tricky topic. Before attempting to integrate real-time audio into an AWE Core OS system, please ensure that the integrator has a basic understanding of digital audio and real-time audio processing. Here are some helpful links.

Giulio Moro - Assessing the stability of audio code for real time low latency embedded processing

RealTime Audio Integration Steps

  1. Verifying Audio HW IO with a Passthrough Ensure that audio can be cleanly passed between input/output without the AWE Core OS involved in the signal path. A simple sine wave input into the system can often be the best audio source for this type of test, as any distortion or dropouts are more easily audible than with a more complex signal. This step is critical to ensure a high fidelity audio system, and can vary greatly from platform to platform. For instance, an embedded target might utilize the HW’s audio IO DMA, while Linux systems may use ALSA to drive audio. For Linux systems, see the RTAudio-alsa.c reference application for an example of using ALSA as the audio driver.
  2. Determining Audio HW Settings and Configuring the AWE Instance.
    1. Configure the sample rate and fundamental block size for the audio device. The block size of any layout loaded on the target must be a multiple of this fundamental block size. If the audio device's sampling rate is 44100.0, then the AWE OS Instance’s sampleRate should be set to 44100.0.
    2. Determine the sample format of the audio HW. See the Audio Sample Formatting section below for more information on audio sample formatting.
    3. Determine the Input/Output channel count of the audio device. AWE Core OS needs to be able to import/export data for each available HW channel. For each available hardware input channel, the application will need to call aweOS_audioImportSamples, and, likewise, aweOS_audioExportSamples will need to be called for each available hardware output channel. Using these channel-by-channel functions make it easy to aggregate multiple audio sources into a single, multi-channel input or output. Additionally, the Import and Export functions automatically handle what is referred to as 'channel matching'. Since AWE Core OS is designed to be flexible and Audio Weaver layouts are designed to be portable, the number of channels in a layout need not match the number of HW inputs and outputs in a system. If a layout has more I/O channels than the hardware channel count, then the Import and Export functions will automatically fill the input signal with additional zeroed channels, and will ignore any additional output channels. Similarly, if the layout loaded has fewer channels than the hardware channel count, then the Import and Export functions will ignore the additional HW input channels, and fill the additional HW output channels with zeros.
  3. The Realtime Audio Loop. Most OS based audio drivers allow the user to register a callback function when a full frame of input audio has been collected, or a full frame of output audio is needed. The AWE Core OS audio loop should be implemented in this call back as follows.
    1. In the audio loop, check to see that a valid layout is loaded and that audio has been started with the API calls aweOS_layoutIsValid and aweOS_audioIsStarted.
    2. Call aweOS_audioImportSamples for each input channel and pass in the audio data from the audio device.
    3. Call aweOS_audioExportSamples for each output channel and pass in the audio HW’s output data.
    4. Call aweOS_audioPumpAll

Audio Sample Formatting

The data type of the input and output audio data is determined by the audio hardware. Typically, digital audio is represented as fixed point data in 16, 24, or 32 bit depth. The audio sample formats _SampleType supported by AWE Core OS's aweOS_audioImportSamples and aweOS_audioExportSamples functions are:

Internally, all inputs and outputs to Audio Weaver layouts are of type Sample32bit, also referred to as fract32 within a layout. This is done to guarantee portability of any signal processing layout to any target system, regardless of the hardware's native audio data type. The aweOS_audioImportSamples and aweOS_audioExportSamples functions will convert to and from the Sample32bit data as needed based on the _SampleType argument. If the target's native audio sample formatting is not one of those listed above, then the program will have to convert the data to one of the supported types before using the import and export functions.

Since some common target systems natively support floating point audio, helper functions are provided to convert between float<–>fract32 in AWECoreUtils.h, which is provided in the AWE Core OS package. See the sample-by-sample conversion functions float_to_fract32 and fract32_to_float. See the API in doc AWECoreUtils.h for more info.

Multi-Rate Processing

The AWE Core OS library allows audio to be processed at multiple block rates. For example, consider a system with two processing paths: one that processes time-domain data in blocks of 32 samples and another that processes frequency-domain data in blocks of 64 samples but at 1/2 the block rate of the time-domain path. Each of these processing paths is called a sublayout, and each has a clock divider property equal to the inverse of the relative block rates. In this example, the sublayout with 32 samples has a clock divider of 1, and the sublayout with 64 samples has a clock divider of 2. Such a system is shown in the figure below. It uses BufferUp and BufferDown modules to connect the different block size domains. These modules effectively partition the layout into 2 sublayouts operating at different block rates. When this layout is pumped, the sublayout of 64 samples will only be processed half as often as the sublayout of 32 samples.

Multi-Rate Layout

Real-time constraints dictate that if the 64 sample sub-layout is executed in the same context as the 32 sample sub-layout, both will need to complete processing before the next block of 32 samples arrives or real-time will be broken. This imposes an unnecessarily strict constraint on the 64 sample sub-layout – its processing need only be completed before the next block of 64 samples is accumulated. Thus, its processing time can, in principle, be spread over 2 of the 32 sample block times without breaking real-time requirements. The internal scheduling of layout pumping in AWE Core OS handles this spreading of sublayout execution times to allow for effective multi-rate processing.

See the CPU Affinity for Multi-Rate Designs section for more info about threading and CPU affinity.

Standalone Operation

At this point, the application should be able to load a layout from Audio Weaver Designer and run it on the target via the Tuning Interface. Once a layout in Designer has been tuned and finalized, the application can be updated to load the layout from an AWB file saved to the filesystem, or from a C array compiled directly into the application.

Loading AWB from an Array

From the viewpoint of AWE Core OS, the signal processing layout is described by a data array of binary Audio Weaver commands. This command array is generated by Audio Weaver Designer using the Tools/Generate Target Files menu item and enabling the [BaseName]_initAWB checkbox. The layout is loaded into an AWE Core OS instance by making a call to aweOS_loadAWBFromArray with the command array, its size in 32-bit words, and the AWEOSInstance as arguments. If an error occurs during loading, then the offset of the offending AWB command is returned to the pErrorOffset argument.

INT32 err = aweOS_loadAWBFromArray (pAWE, pCommands,arraySize, &nErrOffset );
if (err)
    // report the error
    printf(“error code %d due to command at position %u\n”, err, nErrOffset);
    // handle the error

aweOS_loadAWBFromArray will load and process the entire array of binary commands included in the pCommands array. If an array of commands needs to be loaded on a remote instance, it can be loaded command by command with the awe_getNextAWBCmd() helper function in AWECoreUtils.h. Each command is parsed so that they can be routed to the remote instance.

Loading AWB from Filesystem

To generate an AWB file from a layout in Designer, use the Tools/Generate Target Files menu and enable the [BaseName].awb checkbox. This .awb file can be saved to the filesystem on the target and aweOS_loadAWBFile can be used to load and process the commands therein. Loading an AWB from a file rather than a C array has the advantage that an AWB file can be swapped out with an updated design without have to recompile the application.

AWE Core OS Scheduling and Priority

The AWE Core OS library handles the scheduling and prioritization of all the internal processing threads. The user application must only set the schedule and priority of the audio loop function, most often implemented as part of the audio driver's callback function. Since each OS has different scheduling and prioritization models, the code to set the audio loop to a high priority level will be application specific. For a Linux system where the application can be executed with root permissions, the following code in the audio loop context sets the priority to a real-time level and the scheduling policy to SCHED_FIFO.

int max_priority = sched_get_priority_max(SCHED_FIFO);
struct sched_param audio_sched_param = {0};
pthread_t currentHandle = pthread_self();
int target_priority = max_priority - 2;
audio_sched_param.sched_priority = target_priority;
pthread_setschedparam(currentHandle, SCHED_FIFO, &audio_sched_param);

Setting up a Control Interface

Control Interface Overview

A control interface lets the system interact with modules in the running layout directly from the firmware. The following API calls define the functionality of the control interface:

Get/set a value of a module:



Get/Set the status of a module (bypassed, active, inactive, muted):



Check if a module exists, and if so return its ClassID:


The following functions provide finer grained control over how module variables get set and are for advanced users:



Control Interface Steps

To access a module and control it via the Control Interface,

Generally, interacting with modules should follow this flow:

    // Does the current AWE model have a Scaler module with this control object ID?
    if (aweOS_ctrlGetModuleClass(g_AWEOSInstance, AWE_Scaler1_gain_HANDLE, &classId) == E_SUCCESS)
        // Check that module assigned this object ID is of module class Scaler
        if (classID == AWE_Scaler1_classID)
            // Query Scaler1 module's current gain value (value is a scaler)
            aweOS_ctrlGetValue(g_AWEOSInstance, AWE_Scaler1_gain_HANDLE, 0.5, 0, AWE_Scaler1_gain_SIZE);

See the LayoutControl.c app for a full example of controlling a module directly from the application.


AWE Core OS supports multiple levels of memory optimization including custom heaps and reduced module sets. The audio processing threads created by AWE Core OS can also be optimized by fixing their cpu affinity at runtime.

Heap Sizing and Placement

AWE Core OS creates default heaps of size 5000000 words when using the aweOS_getParamDefaults API. If the configuration parameters heap members (heap ptrs and heap size's) are left untouched before aweOS_init, then these default heaps are allocated and assigned to the AWEOSInstance. In most development situations, these default heaps will be sufficient and the user can likely leave them untouched.

Although the default heaps are OK for development, the user may want to reduce the size of the heaps to save memory usage at production time. In some situations, they may also want complete control over the heap's memory location itself, rather than letting AWE Core OS allocate the heap internally.

Change Size of Internal Heaps

Overwrite any of the AWEOSConfigParameter's heap size members (fastHeapASize, fastHeapBSize, slowHeapSize) before calling aweOS_init to use a custom sized heap. When a heap size parameter is overwritten, AWE Core OS will internally allocate and assign heaps of the specified sizes. Note that the heap memory location itself is still internal to the AWE Core OS library.

Heap Memory Location

If a user wants complete control over a heap (size AND memory location), AWEOSConfigParameter's heap pointer members (pSlowHeap, pFastHeapA, pFastHeapB) can be overwritten with pointers to user allocated memory.

If the AWEOSConfigParameter's heap pointers are being overwritten, then the heap size members must also be overwritten to the size of the custom heap. Passing in a custom heap and no size will result in an error when initializing.

UINT32 customSlowHeap[MY_CUSTOM_SIZE];
configParams.pSlowHeap = customSlowHeap;
configParams.slowHeapSize = MY_CUSTOM_SIZE;

Audio Weaver Designer can generate the absolute smallest heap sizes needed for a specific layout via Tools->Generate Target Files->[BaseName]_HeapSize.h.

This can greatly reduce the memory footprint and aid in optimizing a system. Use these generated heap sizes to overwrite the heap size configuration parameters of AWE Core OS.

Module List Optimization

The ModuleList.h file that is delivered with AWE Core OS contains a complete set of Audio Weaver modules available in the library. This is great for designing layouts during development, but when the design is complete, the user may want to remove the unneeded modules to reduce the size of the application.

To trim the module list, simply remove the unused modules from the LISTOFCLASSOBJECTS in ModuleList.h. The module list is passed in as an argument to the aweOS_init function at build time, and only the module's in the list will be included in the application.

See the Declaring the Required Variables section for more implementation details regarding the module list.

Audio Weaver Designer can generate a new ModuleList.h file that contains only the module's used in a given layout. From Designer do Tools->Generate Target Files->[BaseName]_ModuleList.h.

Replace the default ModuleList.h with this trimmed version, and rebuild the application.

3rd party or user created modules can also be added to the application by adding the modules to ModuleList.h and linking the module libraries to the executable.

Threading and CPU Affinity for Multi-Rate Designs

Threading in AWE Core OS

AWE Core OS creates/manages a unique processing thread for each sublayout in a design. For example, a Multi-Rate design with two clockdivided sublayouts (See the Multi-Rate section) would create two pumpthreads named "awe_pumpthread0" and "awe_pumpthread1".

It is important to note that these threads are independent of the user's audio callback thread (where aweOS_audioImportSamples / aweOS_audioExportSamples and aweOS_audioPumpAll are being invoked). The user's audio callback fills the aweOS import buffers with new samples, exports the latest available data from the AWE OS output buffers, and then calls aweOS_audioPumpAll. The aweOS_audioPumpAll function then coordinates the created pumpthreads to execute as needed. The aweOS_audioPumpAll function does not block until the individual pump threads are completed.

In the case of the 2 sublayout model mentioned above, the following threads would be seen in top/htop in a Linux system.

    ./<AWE Core OS Application Parent Process>
        awe_workThread (not an audio thread, but also high priority and time critical)
        awe_tcpThread (not an audio thread, created upon @ref aweOS_tuningSocketOpen

If htop is not showing the names listed above, go to Setup (F2) -> Display Options and enable "Show custom thread names" as seen below. Enabling the Tree view display option is also helpful.

htop Thread Names

Priority Levels

Each operating system will have different methods to update the priority the process is given by the scheduler. The following sections describe Linux specific operations but the general theory can be applied to any OS.

Because the Linux kernel decides the scheduling or processes, the audio threads and the workThread need to be run at the highest possible priority so as not to be pre-empted by less critical processes. AWE Core OS internally sets the pumpthread's priority level based on the audiocallback's priority level (cascading downward). For example, if the audiocallback thread shown above was at priority level 99, then the pumpthread 0 would be set to 98, pumpthread1 to 97, and the workThread to 96.

This requires that the user places their audiocallback thread at a high enough priority to leave room for the number of supported threads (AWEOSConfigParameters.numThreads), as well as the workThread. To ensure that the priority is high enough and that the audio threads aren't unfairly interrupted, it is recommended to simply set the audiocallback's priority to 99. The audiocallback should always be the highest priority, and the workthread should always be just under the lowest pumpthread.

CPU Affinity

The Linux kernel also has control over which cpu a thread executes on, and may choose to migrate the threads to different cpu's at any point. This can be problematic for a number of reasons, but is easily avoided by fixing cpu affinity. To fix all threads in an AWE Core OS application to a single CPU (OK for low-load designs), simply run the executable with taskset and the desired physical CPU.

    taskset -c 0 ./RTAudio-alsa

The command above would run the RTAudio-alsa example app and ALL of its threads exclusively on CPU 1. This may be safer than letting the kernel migrate threads freely, but it also does not fully utilize the processing capabilities of multi-core hardware.

Generally, audio data is dropped when a physical CPU's load approaches/exceeds 100%. Forcing all of aweOS' threads to share a single CPU will cause audio dropouts on that CPU much sooner than if the pumpthreads were distributed to their own CPU's. When everything is forced to one CPU, the other physical CPU's are sitting idle and unutilized. This is highly inefficient, especially in a Multi-Rate design where multiple pumpthreads are running.

AWE Core OS Systems can be highly optimized by assigning strict CPU affinity to its internal threads. The CPU affinity of a thread can also be set with the taskset command. The following shell script will search for a parent process containing the string "RTAudio", and all child processes containing the string "pumpthread". It sets the pumpthreads to their own dedicated CPUs.

This script assumes that 4 physical cores are available, and therefore assigns a max of 4 pumpthreads. It also assumes that the application name contains the string "RTAudio" (Try using the RTAudio-alsa example)

    parentPIDgrep=$(pgrep --list-name RTAudio)
    parentPIDarray=( $parentPIDgrep )
    echo "Found parent process $parentProcessName at pid $parentPID"

    processList="$(ps H -o 'tid comm' $parentPID)"
    processes=( $processList )
    for process in "${!processes[@]}"
            if [[ ${processes[process]} =~ "pumpthread" ]];
                echo "found pumpthread ${processes[process]}"

    for pumpthread in "${!PUMPTHREAD_PID_ARRAY[@]}"
            splitPID=( $fullElement )
            if [[ $threadIdx == "0" ]];
                tasksetout=$(taskset -p 0x11 $PID)
            elif [[ $threadIdx == "1" ]];
                tasksetout=$(taskset -p 0x12 $PID)
            elif [[ $threadIdx == "2" ]];
                tasksetout=$(taskset -p 0x14 $PID)
            elif [[ $threadIdx == "3" ]];
                tasksetout=$(taskset -p 0x18 $PID)
            declare -i COREINT
            echo "set $PID cpu affinity to core $COREINT"

The user has total control of thread cpu affinity with taskset, and this script can be customized to suit a specific system.

Multi Instance

Multi Instance Introduction

Before setting up a multi instance tuning interface, it's recommended to first use and understand a single instance tuning interface. The HelloWorld.c example app is a good place to start.

AWE Core OS systems can contain multiple AWEOS Instances. Though each instance is unique and independent, AWE Core OS supports a single TCP tuning interface socket for up to 31 instances. This feature is demonstrated in the Multi-Instance example app as "single socket" mode. When AWE Server is connected to a multi-instance single socket, a dropdown will appear in the top left corner (the same is true in Designer). Use these dropdown menu's to toggle between sending commands to individual AWEOS Instances.

AWE Core OS also supports opening a tuning socket for each instance on unique port numbers (demonstrated in the Multi-Instance example app as "twosocket" mode). While operating in this mode, only one instance can be controlled at a time from the PC. To control both instances, AWE Server needs to change its connection back and forth, or multiple PCs must be connected to the device.

For more implementation details of multiple sockets, please see the Multi-Instance.c example app.

Multi Instance Tuning Interface Setup

  1. Declare an array of multiple AWEOSInstance 's. Also create a unique AWEOSConfigParameters for each instance, and populate them with defaults.
  2. Overwrite the "instanceID" member of each AWEOSConfigParameters struct in increments of multiples of 16. For example, a 3 instance system would be configured with instanceID's 0,16, and 32. AWEOSInstance 's have an "instanceID" parameter in the associated AWEOSConfigParameters configuration structure. Similarly, AWE Core tuning commands always contain a prefixed address called “instanceID”, which specifies the command's destination. For a single instance system, the AWEOSInstance 's "instanceID" is always 0, and all incoming packets are always addressed to 0.
  3. Initialize all instance's by calling aweOS_init for each AWEOSInstance and its corresponding AWEOSConfigParameters (each of which now has a unique instanceID).
  4. After all instance's are successfully initialized, open the tuning interface with the aweOS_tuningSocketOpen function. Pass it a pointer to the array of instance's, the desired port number for the socket, and the number of instances (elements in the instance array).
  5. Connect to AWE Server and verify that the dropdown menu appears, and toggle between instance's/

Custom Tuning Interface and Multi-Instance

If a custom tuning interface is desired (RS232, USB, etc.), then the application creator is responsible for the routing/processing of AWE Core tuning commands between multiple AWEOSInstance 's. This is described in the AWECore documentation "Multi-Instance" section.

Troubleshooting and Common Pitfalls

Double Pointers

Although most of the AWE Core OS API functions take the AWEOSInstance argument as a single pointer (pass by reference), a few of the functions require a double pointer (pass by reference to reference). The functions that require double pointer arguments are aweOS_init and aweOS_tuningSocketOpen. For example aweOS_audioIsStarted would be called like...

AWEOSInstance *g_AWEOSInstance;
    UINT32 isStarted = aweOS_audioIsStarted(g_AWEOSInstance);

while aweOS_init would be called like...

AWEOSInstance *g_AWEOSInstance; 
     aweOS_init(&g_AWEOSInstance, &configParams, moduleDescriptorTable, moduleDescriptorTableSize); 

Notice that the instance itself is declared as a pointer, so for the functions that require a double pointer, we pass a reference to that pointer.

Specifying Custom Heaps without Specifying Heap Size

If the AWEOSConfigParameter's heap pointers are being overwritten, then the heap size members must also be overwritten to the size of the custom heap. If the user wants to use specific memory regions for heaps, then the application must allocate the memory for the heaps, set the heap pointers to this memory, and set the heapSize members of the AWEOSConfigParameter's to the appropriate sizes. Passing in a custom heap and a size of zero will result in an error when initializing, but passing mismatched heap pointers and sizes will likely lead to memory corruption.

Enabling Real Time Audio with the RTAudio-alsa Example

For information about how to use the RTAudio-alsa sample app with a specific audio device, please see

ALSA Devices

Audio Recording

In order to assist in debugging audio paths and layout input/outputs, there is an option to enable recording of the audio that is processed by the loaded layout using the function aweOS_audioRecordingEnable. This will produce .wav files for both the input and output audio of the layout and can be useful for detecting issues with audio drivers and debugging unexpected results. Also refer to aweOS_audioRecordingDisable and aweOS_audioRecordingRegisterNotificationCallback for more details.