SPARK Audio Core

Integrating the Audio Core is particularly useful for testing a SPARK Audio app or a custom app without the need to implement all the complex details involved in handling audio transfers and packets. To achieve this integration, it is necessary to implement the backend that manages audio functionality.

Note

Integrating the Audio Core is optional and only necessary if audio applications are being developed.

Implement the Backend

To ensure proper integration of the Audio Core on custom hardware, a backend that supports audio data flow and codec operations must be developed. This requires implementing the necessary function prototypes defined in core/audio/sac_hal_facade.h.

An example of how to implement the Endpoint Interface is described below.

/** @brief Initialize the audio endpoint interfaces.
 *
 *  @param[out] producer_iface  Producer audio endpoint interface.
 *  @param[out] consumer_iface  Consumer audio endpoint interface.
 */
void sac_facade_audio_endpoint_init(sac_endpoint_interface_t *producer_iface, sac_endpoint_interface_t *consumer_iface);

Handling CDC is a key part of the Audio Core, as it ensures proper audio data synchronization across different clock domains. CDC functions are included in the facade to support both the PLL-based approach used by the Quasar board and the packet interpolation approach used by the EVK1.4 board, providing flexibility for different hardware setups.

/** @brief Initialize the Clock Drift Compensation processing stage.
 *
 *  @param[in]  format  Audio sample format used in the CDC processing.
 *  @param[out] status  Status code.
 *  @return Reference to the initialized CDC processing stage.
 */
sac_processing_t *sac_facade_cdc_processing_init(sac_sample_format_t format, sac_status_t *status);
/** @brief Format the Clock Drift Compensation statistics as a string of characters.
 *
 *  @param[out] buffer  Buffer where to put the formatted string.
 *  @param[in]  size    Size of the buffer.
 *  @param[out] status  Status code.
 *  @return The formatted string length, excluding the NULL terminator.
 */
int sac_facade_cdc_format_stats(char *buffer, uint16_t size, sac_status_t *status);

Implement the Endpoint Interface

To manage audio data flow, the producer and consumer endpoint interfaces require three key actions: one for packet reception or transmission, and two for starting and stopping processes. Refer to the Audio Endpoint section in the Audio Core documentation for more details.

Below is an implementation example for the Quasar board.

Quasar Endpoints Interface implementation example

  1. Implement three functions to perform the three key actions for both the producer and consumer.

    Handle packet reception and transmission :

    /** @brief Produce Endpoint of the audio codec.
     *
     *  @param[in]  instance  Endpoint instance (not used).
     *  @param[out] samples   Location to put produced samples.
     *  @param[in]  size      Size of samples to produce in bytes.
     *  @return Number of bytes produced (always 0 since production is delayed).
     */
    static uint16_t ep_i2s_action_produce(void *instance, uint8_t *samples, uint16_t size)
    {
        (void)instance;
    
        quasar_audio_sai_read_non_blocking(samples, size);
    
        return 0;
    }
    
    /** @brief Consume Endpoint of the audio codec.
     *
     *  @param[in] instance  Endpoint instance (not used).
     *  @param[in] samples   Samples to consume.
     *  @param[in] size      Size of samples to consume in bytes.
     *  @return Number of bytes consumed (always 0 since consumption is delayed).
     */
    static uint16_t ep_i2s_action_consume(void *instance, uint8_t *samples, uint16_t size)
    {
        (void)instance;
    
        quasar_audio_sai_write_non_blocking(samples, size);
    
        return 0;
    }
    

    Start the process :

    /** @brief Start the endpoint when used as a producer.
     *
     *  @param[in] instance  Endpoint instance (not used).
     */
    static void ep_i2s_start_produce(void *instance)
    {
        (void)instance;
    
        quasar_audio_sai_start_read_non_blocking();
    }
    
    /** @brief Start the endpoint when used as a consumer.
     *
     *  @param[in] instance  Endpoint instance (not used).
     */
    static void ep_i2s_start_consume(void *instance)
    {
        (void)instance;
    
        quasar_audio_sai_start_write_non_blocking();
    }
    

    Stop the process :

    /** @brief Stop the endpoint when used as a producer.
     *
     *  @param[in] instance  Endpoint instance (not used).
     */
    static void ep_i2s_stop_produce(void *instance)
    {
        (void)instance;
    
        quasar_audio_sai_stop_read_non_blocking();
    }
    
    /** @brief Stop the endpoint when used as a consumer.
     *
     *  @param[in] instance  Endpoint instance (not used).
     */
    static void ep_i2s_stop_consume(void *instance)
    {
        (void)instance;
    
        quasar_audio_sai_stop_write_non_blocking();
    }
    
  2. Assign these functions to their respective endpoint interfaces.

        codec_producer_iface->action = ep_i2s_action_produce;
        codec_producer_iface->start = ep_i2s_start_produce;
        codec_producer_iface->stop = ep_i2s_stop_produce;
    }

    if (codec_consumer_iface != NULL) {
        codec_consumer_iface->action = ep_i2s_action_consume;
        codec_consumer_iface->start = ep_i2s_start_consume;
        codec_consumer_iface->stop = ep_i2s_stop_consume;
    }
}

/* PRIVATE FUNCTIONS **********************************************************/
/** @brief Produce Endpoint of the audio codec.
 *