![]() |
![]() |
|
SimpleLink Audio Plugin
|
Generic interface for audio input/output. More...
Modules | |
| AudioHAL Callbacks | |
| AudioHAL application callback functions. | |
Data Structures | |
| struct | AudioHAL_Config_ |
| AudioHAL Global configuration. More... | |
| struct | AudioHAL_FxnTable |
| The definition of a AudioHAL function table that contains the required set of functions to control a specific AudioHAL implementation. More... | |
| struct | AudioHAL_Params |
| AudioHAL Parameters. More... | |
Macros | |
| #define | AUDIOHAL_DEFAULT_BUF_DEPTH 4 |
| The default buffer depth to be used by the AudioHAL. More... | |
| #define | SIZEOF_AUDIOHAL_BITDEPTH_24 (3*sizeof(uint8_t)) |
| SIZEOF_AUDIOHAL_BITDEPTH_24. More... | |
Typedefs | |
| typedef void(* | AudioHAL_closeFxn) (AudioHAL_Handle handle) |
| A function pointer to a specific implementation of AudioHAL_close(). | |
| typedef struct AudioHAL_Config_ | AudioHAL_Config |
| AudioHAL Global configuration. More... | |
| typedef struct AudioHAL_Config_ * | AudioHAL_Handle |
| A handle to an AudioHAL object. More... | |
| typedef void(* | AudioHAL_initFxn) (AudioHAL_Handle handle) |
| A function pointer to a specific implementation of AudioHAL_initFxn(). | |
| typedef AudioHAL_Handle(* | AudioHAL_openFxn) (AudioHAL_Handle handle, const AudioHAL_Params *params) |
| A function pointer to a specific implementation of AudioHAL_open(). | |
| typedef AudioHAL_Status(* | AudioHAL_readBufGetFxn) (AudioHAL_Handle handle, void *frame) |
| A function pointer to a specific implementation of AudioHAL_readBufGet(). | |
| typedef AudioHAL_Status(* | AudioHAL_startStreamFxn) (AudioHAL_Handle handle, AudioHALDir dirToStart) |
| A function pointer to a specific implementation of AudioHAL_startStream(). | |
| typedef AudioHAL_Status(* | AudioHAL_stopStreamFxn) (AudioHAL_Handle handle, AudioHALDir dirToStop) |
| A function pointer to a specific implementation of AudioHAL_stopStream(). | |
| typedef AudioHAL_Status(* | AudioHAL_writeBufPutFxn) (AudioHAL_Handle handle, const void *frame) |
| A function pointer to a specific implementation of AudioHAL_writeBufPut(). | |
Enumerations | |
| enum | AudioHAL_BitDepth { AUDIOHAL_BITDEPTH_16 = 16U, AUDIOHAL_BITDEPTH_24 = 24U, AUDIOHAL_BITDEPTH_32 = 32U } |
| Audio HAL Bit Depth. More... | |
| enum | AudioHAL_Status { AUDIOHAL_SUCCESS = 0x00U, AUDIOHAL_DATA_OVERFLOW = 0x01U, AUDIOHAL_DATA_UNDERFLOW = 0x02U, AUDIOHAL_CMD_FAILED = 0x03U, AUDIOHAL_INVALID_PARAM = 0x04U } |
| AudioHAL status. More... | |
| enum | AudioHALChannels { AUDIOHAL_CHANNELS_MONO = 0x01U, AUDIOHAL_CHANNELS_STEREO = 0x02U } |
| AudioHAL Channels. More... | |
| enum | AudioHALDir { AUDIOHAL_NONE = 0x00U, AUDIOHAL_INPUT = 0x01U, AUDIOHAL_OUTPUT = 0x02U, AUDIOHAL_INPUT_OUTPUT = 0x03U } |
| AudioHAL Direction. More... | |
| enum | AudioHALEvent { AUDIOHAL_STREAM_STARTED = 0x01U, AUDIOHAL_STREAM_STOPPED = 0x02U, AUDIOHAL_STREAM_ERROR = 0x03U } |
| AudioHAL Events. More... | |
| enum | AudioHALRole { AUDIOHAL_SLAVE = 0x01U, AUDIOHAL_MASTER = 0x02U } |
| AudioHAL Direction. More... | |
Functions | |
| void | AudioHAL_close (AudioHAL_Handle handle) |
| Function to close a AudioHAL interface specified by the AudioHAL handle. More... | |
| void | AudioHAL_init (void) |
| Function to initialize the audio interface. | |
| AudioHAL_Handle | AudioHAL_open (uint_least8_t index, const AudioHAL_Params *params) |
| Function to open a given AudioHAL implementation. More... | |
| void | AudioHAL_Params_init (AudioHAL_Params *params) |
| Function to initialize the AudioHAL_Params struct to its defaults. More... | |
| AudioHAL_Status | AudioHAL_readBufGet (AudioHAL_Handle handle, void *frame) |
| Function to get a frame from the AudioHAL's input buffer. More... | |
| AudioHAL_Status | AudioHAL_startStream (AudioHAL_Handle handle, AudioHALDir dirToStart) |
| Function to begin stream of audio. More... | |
| AudioHAL_Status | AudioHAL_stopStream (AudioHAL_Handle handle, AudioHALDir dirToStop) |
| Function to stop stream of audio. More... | |
| AudioHAL_Status | AudioHAL_writeBufPut (AudioHAL_Handle handle, const void *frame) |
| Function to put a frame in the AudioHAL's output buffer. More... | |
Generic interface for audio input/output.
The AudioHAL header file should be included in an application as follows:
The AudioHAL is a hardware abstraction layer for various audio interfaces. The AudioHAL provides APIs for sampling and streaming audio from an application. This enables development of audio applications independent of the underlying driver that is used for sampling the Audio data itself. It is compatible across both multiple interfaces and devices.
The HAL is responsible for initializing, calling, and managing the underlying driver allowing for a minimal set of application code changes when switching between various audio interfaces.
The HAL provides a stream based API for getting audio data into and out from the application. It is well suited for low latency RF enabled audio applications.
The AudioHAL reuses the same design paradigm as the TI drivers or Display middleware. API calls operate on an instance of the HAL which is specified by a handle. A handle is really a pointer to an instance of a specific AudioHAL_Config. A call to open initializes and sets up an instance of the HAL and close will shut it down and close it. Open should be called when the application wishes to use a specific configuration of the HAL and close should be called when the application no longer needs access to the HAL.
Configurations of the HAL are defined in the board file. This enables a decoupling of the application and the hardware configuration.
Unlike TI drivers, the entries in the AudioHAL config table correspond to external hardware (e.g. BoosterPacks or breakout boards) that have audio capability. Each AudioHAL object has the same member variables (HW Attrs, object, function table pointer) but their implementation is different. For example PDM is unidirectional while I2S can be bidirectional. In both cases, the entire application can be built on AudioHAL without changing APIs.
A sample board file entry is shown below:
The structure above tells us that the AudioHAL on this particular board file supports interfacing to external codec devices via I2S. It can be opened from the application as below
It is always recommended to check for a valid handle before using any further APIs, an example is shown below:
The parameters are passed in as part of the open call and are common to all HAL implementations. They will configure the HAL for a given set of audio parameters and will setup the necessary hardware to provide a stream with the given parameters. See AudioHAL_Params for more information about the various parameters. Parameters should be initialized to a known value using AudioHAL_Params_init. The default parameters are defined in AudioHAL.c, but can be set as below:
The parameters above are required for normal operation of the interface. The HAL also relies on the user providing valid parameters. For example if 2 channels are specified (e.g. AUDIOHAL_CHANNELS_STEREO), the HAL expects that the buffer pointed to by the HAL will hold enough memory for numChannels*frameSize samples. The buffering system is described below.
As mentioned above, the AudioHAL ultimately owns and manages the underlying drivers required to implement an interface (e.g. I2S, PDM), however, there may be a need to modify the driver parameters directly to modify the defaults used by the driver. The AudioHAL supports this by way of an arg parameter. The arg parameter is interpreted by the low level implementation as a pointer to the params structure for that driver. For example when using AudioHALCodec which is designed for connecting to I2S based codec devices, the arg parameters will be interpreted as I2S_Params.
See below for an example of using the arg parameter to override specific parameters in the underlying driver. It should be noted that this usually isn't necessary, but is a feature available to users who need this level of customization
The AudioHAL notifies the application of activity via callback. These callbacks are usually executed from the underlying driver callbacks, and thus execute in an elevated context (e.g. SWI, HWI). Callbacks should be optimized for short execution and wherever possible critical sections should be avoided in the callbacks. The section below will explain the role of each of the callbacks. As mentioned above, the callbacks are required for the HAL to function properly and must be implemented by the application.
The data needed callback is invoked when the low level audio interface is configured for output (e.g. AUDIOHAL_OUTPUT or AUDIOHAL_INPUT_OUTPUT) and requires new audio data from the application to be written to the low level interface. It also means that a buffer slot is available in the HAL to accept this data.
On reception of the data needed callback the application is recommended to call @ ref AudioHAL_writeBufPut. This will queue a buffer up to be written by the underlying interface at the tail of the queue. AudioHAL_writeBufPut must be called sufficiently often by the application in order to ensure that underflow does not occur inside the HAL. The AudioHAL_dataNeededCB will notify the application as buffers are consumed (i.e. as driver consumes frames) so based on the AudioHAL_Params::writeBufDepth the application can discern how likely underflow is and mitigate it.
The data ready callback is invoked when the low level audio interface is configured for input (e.g. AUDIOHAL_INPUT or AUDIOHAL_INPUT_OUTPUT) and the interface has new Audio data ready for consumption by the application. It also means that a buffer slot inside the HAL has been consumed by an incoming audio frame.
On reception of the data ready callback, the application is recommended to call AudioHAL_readBufGet. This will remove a buffer from the head of the input queue. AudioHAL_readBufGet must be called sufficiently often to ensure that the queue is not overflow by the low level driver. The AudioHAL_dataReadyCB will notify the application as the low level driver fills up the queue. AudioHAL_Params::readBufDepth determines how many buffer entries are in the queue, and determines how many buffers may be queued up by the low level driver before data will be lost due to overflow.
The AudioHAL is responsible for initializing and managing the actual sample buffers that store the samples that make up an audio frame. A frame is a single buffer of samples. The size and properties of the frame are determined by the following AudioHAL_Params
An Audio Frame must be a contiguous block of memory. It is the application's responsibility to allocate the memory for the frames. For example, a single frame with two channels would look like this where N is the frame size.
| chan1 | chan2 |
|---|---|
| chan1Samp[0] | chan2Samp[0] |
| chan1Samp[1] | chan2Samp[1] |
| chan1Samp[2] | chan2Samp[2] |
| ... | ... |
| chan1Samp[N] | chan2Samp[N] |
Each sample can represent multiple bits. Samples are stored little endian. For example, a 24-bit sample look be shown as below where low blocks are low addresses.
| 24 bit sample |
|---|
| samp0[7:0] |
| samp0[15:8] |
| samp0[23:16] |
With the data above, a single frame with samples of uint16_t type and two channels could be allocated using the following static buffer
It could also be dynamically allocated using the following call
A single buffer of this size will be sent to/received from the HAL with a call to AudioHAL_writeBufPut or AudioHAL_readBufGet respectively.
However the HAL requires multiple frames to be buffered up at once to enable the application to operate on a buffer while another is being used by the driver. This is discussed in the next section.
The buffer depth is defined as the number of audio frames that the HAL can queue for each direction (e.g. read, write). The depth is configurable at initialization, but cannot be changed during stream. This allows for a constant, predictable audio latency. In the HAL the latency is defined as the buffer depth times the length of each frame. Increasing the latency frees up processing time for the main CPU before it needs to provide another frame, but is done at the cost of RAM allocation.
The buffer depth is configured with the AudioHAL_Params::readBufDepth and AudioHAL_Params::writeBufDepth parameters.
The parameters AudioHAL_Params::readBuf and AudioHAL_Params::writeBuf are pointers to the buffer of audio frames for the read and write interface. These must point to a contiguous memory block that can hold at least bufDepth number of frames.
For example static creation of read and write buffers for a bitDepth of 16 can be set as below
the same buffers could be allocated using a dynamic approach
The buffers above would use the following parameters to initialize the HAL.
There is not a type for 24-bit data in C, so it must be represented as uint8_t. In order to write code that is portable across devices, it is recommended to use the macro @ ref SIZEOF_AUDIOHAL_BITDEPTH_24 to set the size of these buffers.
The need for this is because the memory slot length a 24-bit sample differs between CC32xx and CC26xx/CC13xx.
It is important to note that the bitDepth parameter only configures the memory slot length of a sample. The HAL will configure the underlying serial interface (e.g. I2S) accordingly. However, if fine grained tweaks are needed (i.e. before or after word padding). This should be done via the AudioHAL_Params::arg parameter.
Buffers will be queued up in a List using the TI List module. The list will be circular, meaning the head and tail point to one another.
A sample list of buffers when bufDepth is set to 3 is shown below.
* /---------------------------------------------------------------------------------\ * | /---------------------------------------------------------------------------\ | * | | | | * | | |----------------| |----------------| |----------------| | | * | \--+ List Elem |<-------+ List Elem |<-------+ List Elem |<--/ | * \---->| pBuf +------->| pBuf +------->| pBuf +------/ * |-------+--------| |-------+--------| |-------+--------| * | | | * | | | * V V V * |----------------| |----------------| |----------------| * | Frame | | Frame | | Frame | * | Buf | | Buf | | Buf | * | | | | | | * | | | | | | * | | | | | | * | | | | | | * |----------------| |----------------| |----------------| * *
The HAL is stream based, meaning that once the flow of data is enabled it runs continuously until stopped. The direction of the stream is defined by the direction parameter in the AudioHAL_Params.
The stream can be started as below:
The stream can be stopped as below P
Once a stream is enabled the user provided callbacks will be invoked and data can be put into and read from the stream using the AudioHAL_readBufGet and AudioHAL_writeBufPut APIs.
Here is an example of reading a buffer from the stream
Note that the put/get functions perform a deep copy, which means they require an input buffer and output buffer to operate on.
| #define AUDIOHAL_DEFAULT_BUF_DEPTH 4 |
The default buffer depth to be used by the AudioHAL.
This may be changed via AudioHAL_Params::readBufDepth
| #define SIZEOF_AUDIOHAL_BITDEPTH_24 (3*sizeof(uint8_t)) |
SIZEOF_AUDIOHAL_BITDEPTH_24.
This is a convience macro for determing the side of samples of 24-bit type
Using this macro is the best way to make the code portable across platforms because different devies will use different memory slots to store a 24-bit sample.
For example
When using 24-bit samples, always use the uint8_t type. For example this can be used to declare the read and write buffers as below:
Later these buffers will be consumed by the HAL by way of the AudioHAL_Params see below for example
| typedef struct AudioHAL_Config_ AudioHAL_Config |
AudioHAL Global configuration.
The AudioHAL_Config structure contains a set of pointers used to characterize the AudioHAL interface implementation.
This structure needs to be defined before calling AudioHAL_open() and it must not be changed thereafter.
| typedef struct AudioHAL_Config_* AudioHAL_Handle |
A handle to an AudioHAL object.
This structure hold the various variables needed for one instance of\ an AudioHAL object
| enum AudioHAL_BitDepth |
Audio HAL Bit Depth.
This represents the size of each sample in bits.
| Enumerator | |
|---|---|
| AUDIOHAL_BITDEPTH_16 | Each sample is 16-bits |
| AUDIOHAL_BITDEPTH_24 | Each sample is 24-bits |
| AUDIOHAL_BITDEPTH_32 | Each sample is 32-bits |
| enum AudioHAL_Status |
AudioHAL status.
The AudioHAL Status is used to flag the different errors as return codes to AudioHAL API calls
| enum AudioHALChannels |
| enum AudioHALDir |
AudioHAL Direction.
Describes whether the HAL is to be used to read, write, or read and write audio data to the lower layer driver
| enum AudioHALEvent |
| enum AudioHALRole |
| void AudioHAL_close | ( | AudioHAL_Handle | handle | ) |
Function to close a AudioHAL interface specified by the AudioHAL handle.
| handle | A AudioHAL_Handle returned from AudioHAL_open() |
| AudioHAL_Handle AudioHAL_open | ( | uint_least8_t | index, |
| const AudioHAL_Params * | params | ||
| ) |
Function to open a given AudioHAL implementation.
Function to open a given AudioHAL implementation specified by the particular index value.
| index | Logical peripheral number for the AudioHAL indexed into the AudioHAL_config table |
| params | Pointer to a parameter block. If NULL, default parameter values will be used. All the fields in this structure are RO (read-only). |
| void AudioHAL_Params_init | ( | AudioHAL_Params * | params | ) |
Function to initialize the AudioHAL_Params struct to its defaults.
| params | An pointer to AudioHAL_Params structure for initialization. |
Defaults values are:
| AudioHAL_Status AudioHAL_readBufGet | ( | AudioHAL_Handle | handle, |
| void * | frame | ||
| ) |
Function to get a frame from the AudioHAL's input buffer.
Function to retrieve a frame from the HAL's input buffer. This will also remove the frame from the buffer, thus freeing up a slot in the buffer for another entry.
| handle | A AudioHAL handle returned from AudioHAL_open() |
| frame | A frame buffer provided by AudioHal |
| AudioHAL_Status AudioHAL_startStream | ( | AudioHAL_Handle | handle, |
| AudioHALDir | dirToStart | ||
| ) |
Function to begin stream of audio.
Function to begin an audio stream. The directionality of this stream is determined by the AudioHAL_Params::direction parameter. This will invoke AudioHAL_dataReadyCB when data is ready from input and AudioHAL_dataNeededCB when data is required on the output.
| handle | A AudioHAL handle returned from AudioHAL_open() |
| dirToStart | Which direction to start stream in AudioHALDir |
dirToStart parameter, a NONE stream cannot be started.| AudioHAL_Status AudioHAL_stopStream | ( | AudioHAL_Handle | handle, |
| AudioHALDir | dirToStop | ||
| ) |
Function to stop stream of audio.
Function to stop an audio stream. Callbacks will no longer be invoked and the hardware will be placed in an idle state
| handle | A AudioHAL handle returned from AudioHAL_open() |
| dirToStop | Which direction to stop stream in AudioHALDir |
dirToStop parameter, a NONE stream cannot be stopped.| AudioHAL_Status AudioHAL_writeBufPut | ( | AudioHAL_Handle | handle, |
| const void * | frame | ||
| ) |
Function to put a frame in the AudioHAL's output buffer.
Function to put a frame in the HAL's output buffer. This will also consume a slot in the buffer list and copy the buffer into the slot.
| handle | A AudioHAL handle returned from AudioHAL_open() |
| frame | A pointer to a frame buffer |