audio_element对象是使用ADF开发的应用程序的基本构建块。实际上,每个解码器,编码器,滤波器,输入流或输出流都是音频元素。
Element的一般功能是在输入中获取一些数据,对其进行处理,然后输出到下一个。每个元素都作为单独的任务运行。
为了能够控制从输入,处理到输出的数据生命周期的特定阶段,audio_element对象提供了在每个阶段触发回调. 可用的回调函数有七种类型:打开,查找,处理,关闭,销毁,读取和写入.打开,查找,处理,关闭,销毁,读取和写入.在audio_element_cfg_t 中配置。
esp-adf/components/audio_pipeline/include /audio_element.h
esp-adf/components/audio_pipeline/audio_element.c
typedef enum {
AEL_IO_OK = ESP_OK,
AEL_IO_FAIL = ESP_FAIL,
AEL_IO_DONE = -2,
AEL_IO_ABORT = -3,
AEL_IO_TIMEOUT = -4,
AEL_PROCESS_FAIL = -5,
} audio_element_err_t;
typedef enum {
AEL_STATE_NONE = 0,
AEL_STATE_INIT,
AEL_STATE_RUNNING,
AEL_STATE_PAUSED,
AEL_STATE_STOPPED,
AEL_STATE_FINISHED,
AEL_STATE_ERROR
} audio_element_state_t;
typedef enum {
AEL_MSG_CMD_NONE = 0,
AEL_MSG_CMD_ERROR = 1,
AEL_MSG_CMD_FINISH = 2,
AEL_MSG_CMD_STOP = 3,
AEL_MSG_CMD_PAUSE = 4,
AEL_MSG_CMD_RESUME = 5,
AEL_MSG_CMD_DESTROY = 6,
// AEL_MSG_CMD_CHANGE_STATE = 7,
AEL_MSG_CMD_REPORT_STATUS = 8,
AEL_MSG_CMD_REPORT_MUSIC_INFO = 9,
AEL_MSG_CMD_REPORT_CODEC_FMT = 10,
AEL_MSG_CMD_REPORT_POSITION = 11,
} audio_element_msg_cmd_t;
typedef enum {
AEL_STATUS_NONE = 0,
AEL_STATUS_ERROR_OPEN = 1,
AEL_STATUS_ERROR_INPUT = 2,
AEL_STATUS_ERROR_PROCESS = 3,
AEL_STATUS_ERROR_OUTPUT = 4,
AEL_STATUS_ERROR_CLOSE = 5,
AEL_STATUS_ERROR_TIMEOUT = 6,
AEL_STATUS_ERROR_UNKNOWN = 7,
AEL_STATUS_INPUT_DONE = 8,
AEL_STATUS_INPUT_BUFFERING = 9,
AEL_STATUS_OUTPUT_DONE = 10,
AEL_STATUS_OUTPUT_BUFFERING = 11,
AEL_STATUS_STATE_RUNNING = 12,
AEL_STATUS_STATE_PAUSED = 13,
AEL_STATUS_STATE_STOPPED = 14,
AEL_STATUS_STATE_FINISHED = 15,
AEL_STATUS_MOUNTED = 16,
AEL_STATUS_UNMOUNTED = 17,
} audio_element_status_t;
typedef struct {
int sample_rates; /*!< 采样率 */
int channels; /*!< 当前通道数 1 单声道,2 立体声 */
int bits; /*!< 音频位宽 */
int bps; /*!< 每秒传输位数*/
int64_t byte_pos; /*!< 当前处理的因为位置(偏移量)*/
int64_t total_bytes; /*!< 整个元素大小 */
int duration; /*!< The duration for an element (optional) */
char *uri; /*!<音频保存目录,一般为sd卡或http路径*/
audio_codec_t codec_fmt; /*!< 音频格式 */
audio_element_reserve_data_t reserve_data; /*!< This value is reserved for user use (optional) */
} audio_element_info_t;
typedef esp_err_t (*io_func)(audio_element_handle_t self);
typedef audio_element_err_t (*process_func)(audio_element_handle_t self, char *el_buffer, int el_buf_len);
typedef audio_element_err_t (*stream_func)(audio_element_handle_t self, char *buffer, int len, TickType_t ticks_to_wait,
void *context);
typedef esp_err_t (*event_cb_func)(audio_element_handle_t el, audio_event_iface_msg_t *event, void *ctx);
typedef esp_err_t (*ctrl_func)(audio_element_handle_t self, void *in_data, int in_size, void *out_data, int *out_size);
typedef struct {
io_func open; /*!< Open callback function */
ctrl_func seek; /*!< Seek callback function */
process_func process; /*!< Process callback function */
io_func close; /*!< Close callback function */
io_func destroy; /*!< Destroy callback function */
stream_func read; /*!< Read callback function */
stream_func write; /*!< Write callback function */
int buffer_len; /*!< Buffer length use for an Element */
int task_stack; /*!< Element task stack */
int task_prio; /*!< Element task priority (based on freeRTOS priority) */
int task_core; /*!< Element task running in core (0 or 1) */
int out_rb_size; /*!< Output ringbuffer size */
void *data; /*!< User context */
const char *tag; /*!< Element tag */
int multi_in_rb_num; /*!< The number of multiple input ringbuffer */
int multi_out_rb_num; /*!< The number of multiple output ringbuffer */
} audio_element_cfg_t;
/**
* @brief Initialize audio element with config.
*
* @param config The configuration
*
* @return
* - audio_elemenent handle object
* - NULL
*/
audio_element_handle_t audio_element_init(audio_element_cfg_t *config);
/**
* @brief 将新对象添加到el中。可以通过调用检索它audio_element_getdata
*
* @param[in] el The audio element handle
* @param data The data pointer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_setdata(audio_element_handle_t el, void *data);
/**
* @brief Get context data from element handle object.
*
* @param[in] el The audio element handle
*
* @return data pointer
*/
void *audio_element_getdata(audio_element_handle_t el);
/**
* @brief 设置el 标签名,在整个esp-adf的管道中基于tag查找元素的,所以这个tag必须保证唯一。如果想清除tag 则需要使tag = NULL
*
* @param[in] el The audio element handle
* @param[in] tag The tag name pointer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_tag(audio_element_handle_t el, const char *tag);
/**
* @brief 获取标签名
*
* @param[in] el The audio element handle
*
* @return Element tag name pointer
*/
char *audio_element_get_tag(audio_element_handle_t el);
/**
* @brief 设置audio element 信息
*
* @param[in] el The audio element handle
* @param info The information pointer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_setinfo(audio_element_handle_t el, audio_element_info_t *info);
/**
* @brief 获取audio elements 的信息
*
* @param[in] el The audio element handle
* @param info The information pointer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_getinfo(audio_element_handle_t el, audio_element_info_t *info);
/**
* @brief 设置当前元素的 ulr,如果元素为写入状态则这个url就是保存路径。如果元素为读取状态,则这个ulr就是音频的来源。
*
* @param[in] el The audio element handle
* @param[in] uri The uri pointer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_uri(audio_element_handle_t el, const char *uri);
/**
* @brief 获取ulr
* @param[in] el The audio element handle
*
* @return URI pointer
*/
char *audio_element_get_uri(audio_element_handle_t el);
/**
* @brief 启动 audio element
* 这个函数内部就是按照配置信息创建一个基于freeRTOS的任务函数,并且运行这个任务函数。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_run(audio_element_handle_t el);
/**
* @brief 终止音频元素。使用此功能,audio_element将退出任务功能。注意:此API仅发送请求。当此函数返回时,它实际上并不会立即终止.
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_terminate(audio_element_handle_t el);
/**
* @brief 请求停止音频元素。收到停止请求后,该元素将忽略正在执行的动作(读/写,等待环形缓冲区…)并关闭任务,
* 重置状态变量。注意:此API仅发送请求,当此函数返回时,Element实际上不会停止。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_stop(audio_element_handle_t el);
/**
* @brief audio_element_stop调用函数后,Element任务将执行一些中止过程。
* 该功能将被阻止(时间为DEFAULT_MAX_WAIT_TIME),直到Element Task完成并退出。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_wait_for_stop(audio_element_handle_t el);
/**
* @brief audio_element_stop调用函数后,Element任务将执行一些中止过程。应等待的最大时间量是阻止元素任务停止。
*
* @param[in] el The audio element handle
* @param[in] ticks_to_wait The maximum amount of time to wait for stop
*
* @return
* - ESP_OK, Success
* - ESP_FAIL, Timeout
*/
esp_err_t audio_element_wait_for_stop_ms(audio_element_handle_t el, TickType_t ticks_to_wait);
/**
* @brief 请求音频元素进入“暂停”状态。在这种状态下,任务将等待任何事件。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_pause(audio_element_handle_t el);
/**
* @brief 请求音频元素进入“运行中”状态。在这种状态下,
* 任务将侦听事件并调用回调函数。同时,它将等待,
* 直到输出环形缓冲区的大小/total_size大于或等于wait_for_rb_threshold。* 如果超过了超时时间并且尚未达到环形缓冲区输出,
* wait_for_rb_threshold则该函数将返回。
*
* @param[in] el The audio element handle
* @param[in] wait_for_rb_threshold The wait for rb threshold (0 .. 1)
* @param[in] timeout The timeout
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_resume(audio_element_handle_t el, float wait_for_rb_threshold, TickType_t timeout);
/**
* @brief 为el 增加一个监听器,监听这个el的所有时间
* 任何事件都会通过 el->external_event 将事件信息发送到这个监听器上
*
* @param el The audio element handle
* @param listener The event will be listen to
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_msg_set_listener(audio_element_handle_t el, audio_event_iface_handle_t listener);
/**
* @brief 为el 增加一个回调函数
* 调用者的任何事件都将导致调用回调函数。
*
* @param el The audio element handle
* @param cb_func The callback function
* @param ctx Caller context
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_event_callback(audio_element_handle_t el, event_cb_func cb_func, void *ctx);
/**
* @brief 从el中删除一个监听器
*
* @param[in] el The audio element handle
* @param listener The listener
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_msg_remove_listener(audio_element_handle_t el, audio_event_iface_handle_t listener);
/**
* @brief 设置元素输入环形缓冲区
*
* @param[in] el The audio element handle
* @param[in] rb The ringbuffer handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_input_ringbuf(audio_element_handle_t el, ringbuf_handle_t rb);
/**
* @brief 获取元素输入环形缓冲区
*
* @param[in] el The audio element handle
*
* @return ringbuf_handle_t
*/
ringbuf_handle_t audio_element_get_input_ringbuf(audio_element_handle_t el);
/**
* @brief 设置元素输出环形缓冲区
*
* @param[in] el The audio element handle
* @param[in] rb The ringbuffer handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_output_ringbuf(audio_element_handle_t el, ringbuf_handle_t rb);
/**
* @brief 获取元素输出环形缓冲区。
*
* @param[in] el The audio element handle
*
* @return ringbuf_handle_t
*/
ringbuf_handle_t audio_element_get_output_ringbuf(audio_element_handle_t el);
/**
* @brief 获取当前element的状态
*
* @param[in] el The audio element handle
*
* @return audio_element_state_t
*/
audio_element_state_t audio_element_get_state(audio_element_handle_t el);
/**
* @brief 如果元素正在从输入环形缓冲区请求数据,则此函数将强制其中止。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_abort_input_ringbuf(audio_element_handle_t el);
/**
* @brief 如果元素正在等待将数据写入环形缓冲区输出,则此函数将强制其中止。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_abort_output_ringbuf(audio_element_handle_t el);
/**
* @brief 此函数将等待,直到输出环形缓冲区的大小大于或等于为止size_expect。
* 如果超过了超时时间并且尚未达到环形缓冲区输出,
* size_expect则该函数将返回ESP_FAIL
*
* @param[in] el The audio element handle
* @param[in] size_expect The size expect
* @param[in] timeout The timeout
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_wait_for_buffer(audio_element_handle_t el, int size_expect, TickType_t timeout);
/**
* @brief 元素将通过此功能将事件(状态)发送到事件。
*
* @param[in] el The audio element handle
* @param[in] status The status
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_report_status(audio_element_handle_t el, audio_element_status_t status);
/**
* @brief 元素将通过此功能向事件发送事件(信息)。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_report_info(audio_element_handle_t el);
/**
* @brief 元素将通过此功能向事件发送事件(编解码器格式)。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_report_codec_fmt(audio_element_handle_t el);
/**
* @brief 元素将通过此功能发送带有重复信息的事件。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
* - ESP_ERR_NO_MEM
*/
esp_err_t audio_element_report_pos(audio_element_handle_t el);
/**
* @brief 设置输入读取超时(默认为portMAX_DELAY)。
*
* @param[in] el The audio element handle
* @param[in] timeout The timeout
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_input_timeout(audio_element_handle_t el, TickType_t timeout);
/**
* @brief 设置输出读取超时(默认为portMAX_DELAY)。
*
* @param[in] el The audio element handle
* @param[in] timeout The timeout
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_output_timeout(audio_element_handle_t el, TickType_t timeout);
/**
* @brief 重置输入缓冲区
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_reset_input_ringbuf(audio_element_handle_t el);
/**
* @brief 设置元素完成状态
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_finish_state(audio_element_handle_t el);
/**
* @brief 使用特定命令更改元素的运行状态
*
* @param[in] el The audio element handle
* @param[in] cmd Specific command from audio_element_msg_cmd_t
*
* @return
* - ESP_OK
* - ESP_FAIL
* - ESP_ERR_INVALID_ARG Element handle is null
*/
esp_err_t audio_element_change_cmd(audio_element_handle_t el, audio_element_msg_cmd_t cmd);
/**
* @brief 调用此函数以提供元素输入数据
* 根据使用环形缓冲区或函数回调的设置,Element调用读取环形缓冲区,或调用读取回调函数。
*
* @param[in] el The audio element handle
* @param buffer The buffer pointer
* @param[in] wanted_size The wanted size
*
* @return
* - > 0 number of bytes produced
* - <=0 audio_element_err_t
*/
audio_element_err_t audio_element_input(audio_element_handle_t el, char *buffer, int wanted_size);
/**
* @brief 调用此函数以发送元素输出数据。根据使用环形缓冲区或函数回调的设置,
* Element将调用对环形缓冲区的写操作,或调用写回调函数。
*
* @param[in] el The audio element handle
* @param buffer The buffer pointer
* @param[in] write_size The write size
*
* @return
* - > 0 number of bytes written
* - <=0 audio_element_err_t
*/
audio_element_err_t audio_element_output(audio_element_handle_t el, char *buffer, int write_size);
/**
* @brief 此API允许应用程序为管道中的第一个audio_element设置读取回调,以允许管道与其他系统接口。每当音频元素需要处理数据时,都会调用该回调。
*
* @param[in] el The audio element handle
* @param[in] fn Callback read function. The callback function should return number of bytes read or -1
* in case of error in reading. Note that the callback function may decide to block and
* that may block the entire pipeline.
* @param[in] context An optional context which will be passed to callback function on every invocation
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_read_cb(audio_element_handle_t el, stream_func fn, void *context);
/**
* @brief 该API允许应用程序为管道中的最后一个audio_element设置写回调,
* 以允许管道与其他系统接口。每当音频元素具有需要转发的已处理数据时,都会调用该回调。
*
* @param[in] el The audio element
* @param[in] fn Callback write function
* The callback function should return number of bytes written or -1 in case of error in writing.
* Note that the callback function may decide to block and that may block the entire pipeline.
* @param[in] context An optional context which will be passed to callback function on every invocation
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_write_cb(audio_element_handle_t el, stream_func fn, void *context);
/**
* @brief
*
* @param[in] el The audio element handle
*
* @return QueueHandle_t
*/
QueueHandle_t audio_element_get_event_queue(audio_element_handle_t el);
/**
* @brief 设置输入缓冲区和输出缓冲区已完成
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_ringbuf_done(audio_element_handle_t el);
/**
* @brief 强制执行“ AEL_STATE_INIT”状态。
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_reset_state(audio_element_handle_t el);
/**
* @brief 获取元素输出环形缓冲区的大小。
*
* @param[in] el The audio element handle
*
* @return
* - =0: Parameter NULL
* - >0: Size of ringbuffer
*/
int audio_element_get_output_ringbuf_size(audio_element_handle_t el);
/**
* @brief 设置元素输出环形缓冲区的大小。
*
* @param[in] el The audio element handle
* @param[in] rb_size Size of the ringbuffer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_output_ringbuf_size(audio_element_handle_t el, int rb_size);
/**
* @brief 调用此函数以给定索引从多输入环形缓冲区读取数据
*
* @param el The audio element handle
* @param buffer The buffer pointer
* @param wanted_size The wanted size
* @param index The index of multi input ringbuffer, start from `0`, should be less than `NUMBER_OF_MULTI_RINGBUF`
* @param ticks_to_wait Timeout of ringbuffer
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG
*/
esp_err_t audio_element_multi_input(audio_element_handle_t el, char *buffer, int wanted_size, int index, TickType_t ticks_to_wait);
/**
* @brief C通过多输出环形缓冲区调用此函数写入数据。
*
* @param[in] el The audio element handle
* @param buffer The buffer pointer
* @param[in] wanted_size The wanted size
* @param ticks_to_wait Timeout of ringbuffer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_multi_output(audio_element_handle_t el, char *buffer, int wanted_size, TickType_t ticks_to_wait);
/**
* @brief 设置多输入环形缓冲区元素。
*
* @param[in] el The audio element handle
* @param[in] rb The ringbuffer handle
* @param[in] index Index of multi ringbuffer, starts from `0`, should be less than `NUMBER_OF_MULTI_RINGBUF`
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_set_multi_input_ringbuf(audio_element_handle_t el, ringbuf_handle_t rb, int index);
/**
* @brief 设置多输出环形缓冲区元素。
*
* @param[in] el The audio element handle
* @param[in] rb The ringbuffer handle
* @param[in] index Index of multi ringbuffer, starts from `0`, should be less than `NUMBER_OF_MULTI_RINGBUF`
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG
*/
esp_err_t audio_element_set_multi_output_ringbuf(audio_element_handle_t el, ringbuf_handle_t rb, int index);
/**
* @brief 通过索引获取多输入环形缓冲区元素的句柄。
*
* @param[in] el The audio element handle
* @param[in] index Index of multi ringbuffer, starts from `0`, should be less than `NUMBER_OF_MULTI_RINGBUF`
*
* @return
* - NULL Error
* - Others ringbuf_handle_t
*/
ringbuf_handle_t audio_element_get_multi_input_ringbuf(audio_element_handle_t el, int index);
/**
* @brief 通过索引获取多输出环形缓冲区元素的句柄。
*
* @param[in] el The audio element handle
* @param[in] index Index of multi ringbuffer, starts from `0`, should be less than `NUMBER_OF_MULTI_RINGBUF`
*
* @return
* - NULL Error
* - Others ringbuf_handle_t
*/
ringbuf_handle_t audio_element_get_multi_output_ringbuf(audio_element_handle_t el, int index);
/**
* @brief 提供一种调用元素的方法 open
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_process_init(audio_element_handle_t el);
/**
* @brief 提供一种调用元素的 close
*
* @param[in] el The audio element handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t audio_element_process_deinit(audio_element_handle_t el);
/**
* @brief Call element's `seek`
*
* @param[in] el The audio element handle
* @param[in] in_data A pointer to in data
* @param[in] in_size The size of the `in_data`
* @param[out] out_data A pointer to the out data
* @param[out] out_size The size of the `out_data`
*
* @return
* - ESP_OK
* - ESP_FAIL
* - ESP_ERR_NOT_SUPPORTED
*/
esp_err_t audio_element_seek(audio_element_handle_t el, void *in_data, int in_size, void *out_data, int *out_size);
欢迎关注我的个人网站:zwww.zcxbb.com
知乎专栏:物联网开发入门 - 知乎 (zhihu.com)