更新时间:2023-08-09 09:25:02下载pdf
本文介绍 TKL(TuyaOS Kernel Layer)和 TAL(TuyaOS Abstraction Layer)层音频采集与播放 API 的调用流程。
音频采集:简称 AI(Audio Input),是指通过麦克采集声音,并编码成音频数据。通常 1 秒采集 25 帧。
音频播放:简称 AO(Audio Output),是指使用喇叭播放音频数据。包括提示音,对讲数据等。
音频采集数据为裸数据 PCM。若需要 G711u/a 等格式编码,您需要在应用层处理。
音频播放数据在上层解码为裸数据后,再调用播放接口。AO 播放前后,请注意开关扩音器的功放引脚。
typedef struct {
UINT_T enable; // 1,enable,0,disable
UINT_T card; // audio card num
TKL_AI_CHN_E ai_chn; // audio input channel
TKL_AUDIO_SAMPLE_E sample; // sample
TKL_AUDIO_DATABITS_E datebits; // datebit
TKL_AUDIO_CHANNEL_E channel; // channel num
TKL_MEDIA_CODEC_TYPE_E codectype; // codec type
INT32_T is_softcodec; // 1, soft encode,0, hardware encode
UINT_T fps; // frame per second,suggest 25
INT32_T mic_volume; // mic volume,[0,100]
INT32_T spk_volume; // spk volume,[0,100]
INT32_T spk_volume_offset; // spk volume offset, for adapting different speakers,The default value is 0,[0,100]
INT32_T spk_gpio; // spk amplifier pin number, <0, no amplifier
INT32_T spk_gpio_polarity; // pin polarity, 0 high enable, 1 low enable
void * padta;
}TKL_AUDIO_CONFIG_T; // audio config
#define TAL_AUDIO_CONFIG_T TKL_AUDIO_CONFIG_T
typedef struct{
TKL_MEDIA_FRAME_TYPE_E type; // frame type
CHAR_T *pbuf; // buffer
UINT_T buf_size; // buffer size
UINT_T used_size; // used buffer
UINT64_T pts; // sdk pts
UINT64_T timestamp; // system utc time,unit: ms
TKL_MEDIA_CODEC_TYPE_E codectype; // codec type
TKL_AUDIO_SAMPLE_E sample; // sample
TKL_AUDIO_DATABITS_E datebits; // date bit
TKL_AUDIO_CHANNEL_E channel; // channel num
UINT_T seq; // frame sequence number
}TKL_AUDIO_FRAME_INFO_T; // audio frame
#define TAL_AUDIO_FRAME_INFO_T TKL_AUDIO_FRAME_INFO_T
typedef enum {
TAL_AI_CMD_VOL, // AI volume
} TAL_AI_CMD_E;
typedef enum {
TAL_AO_CMD_VOL, // AO volume, int, val[0, 100]
} TAL_AO_CMD_E;
IPC 设备,暂时只支持 1 路 AI。音频初始化前,注意先初始化视频。
/**
* @brief AI init
*
* @param[in] pconfig: audio config
* @param[in] count: count of pconfig
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ai_init(TAL_AUDIO_CONFIG_T *pconfig, INT32_T count);
/**
* @brief AI start
*
* @param[in] card: card number
* @param[in] chn: channel number
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ai_start(INT32_T card, INT32_T chn);
/**
* @brief AI stop
*
* @param[in] card: card number
* @param[in] chn: channel number
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ai_stop(INT32_T card, INT32_T chn);
/**
* @brief AI get frame
*
* @param[in] card: card number
* @param[in] chn: channel number
* @param[out] pframe: audio frame, pframe->pbuf allocated by upper layer application
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ai_get_frame(INT32_T card, INT32_T chn, TAL_AUDIO_FRAME_INFO_T *pframe);
pframe
,需要给变量 pbuf
分配内存。内存大小建议 640 字节。
音量设置一般在初始化化时配置,启动后通常不修改 AI 的音量。
/**
* @brief AI set
*
* @param[in] card: card number
* @param[in] chn: channel number
* @param[in] cmd
* @param[in] parg
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ai_set(INT32_T card, INT32_T chn, TAL_AI_CMD_E cmd, VOID *parg);
/**
* @brief AO uninit
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ai_uninit(VOID);
IPC 设备,暂时只支持 1 路 AO。
AO 和 AI 初始化,部分平台有顺序要求。通常先初始化 AI,再初始 AO。
VOID **handle
仅供中台设备使用。IPC 不使用。
/**
* @brief AO init
*
* @param[in] pconfig: audio config
* @param[in] count: config count
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ao_init(TAL_AUDIO_CONFIG_T *pconfig, INT32_T count, VOID **handle);
/**
* @brief AO start
*
* @param[in] card: card number
* @param[in] chn: channel number
* @param[out] handle: handle of start
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ao_start(INT32_T card, INT32_T chn, VOID *handle);
OPERATE_RET tal_ao_stop(INT32_T card, INT32_T chn, VOID *handle);
播放的音频数据要求为裸数据。
OPERATE_RET tal_ao_put_frame(INT32_T card, INT32_T chn, VOID *handle, TAL_AUDIO_FRAME_INFO_T *pframe);
AO 音量设置,在 AO 初始后即可。
/**
* @brief AO set
*
* @param[in] card: card number
* @param[in] chn: channel number
* @param[in] handle: the return of start
* @param[in] cmd
* @param[in] parg
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ao_set(INT32_T card, INT32_T chn, VOID *handle, TAL_AO_CMD_E cmd, VOID *parg);
/**
* @brief AO uninit
*
* @return OPRT_OK on success. Others on error, please refer to tkl_error_code.h
*/
OPERATE_RET tal_ao_uninit(VOID *handle);
// 参数配置
.audio[0].enable = 1,
.audio[0].ai_chn = 0,
.audio[0].sample = 8000,
.audio[0].datebits = 16,
.audio[0].channel = 0,
.audio[0].codectype = 101,
.audio[0].fps = 25,
.audio[0].mic_volume = 80,
.audio[0].spk_volume = 80,
.audio[0].spk_gpio = 15,
.audio[0].spk_gpio_polarity = 0,
// 初始化:
ret = tal_ai_init(pinfo->audio, 1);
if (0 != ret) {
TYERROR("tal_ai_init failed,%d\n", ret);
return -1;
}
ret = tal_ao_init(pinfo->audio, 1, NULL);
if (0 != ret) {
TYERROR("tal_ao_init failed,%d\n", ret);
return -1;
}
ret = ty_sys_gpio_init(&spk_gpio);
if (0 != ret) {
TYERROR("tycam_gpio_init failed, %d\n", ret);
return -1;
}
// 音频采集:
ret = tal_ai_start(0, 0);
if (0 != ret) {
TYERROR("ty_dev_ai_start failed,%d\n", ret);
return -1;
}
TAL_AUDIO_FRAME_INFO_T frame = {0};
frame.pbuf = (char *)malloc(640);
frame.buf_size = 640;
ret = tal_ai_get_frame(0, 0, frame);
if (0 != ret) {
// TYERROR("get frame failed type:%d\n", type);
return -1;
}
ret = tuya_g711_encode(TUYA_G711_MU_LAW, (unsigned short *)buf, used_size, tmpBuf, &outLen);
...
// 音频播放:
ret = tal_ao_start(0, 0, handle);
...
ret = tal_gpio_write(spk_gpio, TAL_GPIO_LEVEL_HIGH);
...
ret = tuya_g711_decode(g711Type, (unsigned short *)pbuf, used_size, buf, &outLen);
...
ret = tal_ao_put_frame(0, 0, NULL, pFrame);
...
ret = tal_gpio_write(spk_gpio, TAL_GPIO_LEVEL_HIGH);
...
ret = tal_ao_stop(spk_gpio, TAL_GPIO_LEVEL_HIGH);
...
// 播放音量调节:
ret = tal_ao_set(0, 0, NULL, TAL_AO_CMD_VOL, &spk_volume);
通常,支持视频采集的设备,需要先初始化视频,再初始化 AI。原因是,芯片平台原生 SDK 需要分配一次 MMZ(Media Memory Zone)内存。MMZ 内存是在视频初始化时分配的。
建议 640 字节。由于需要对接三方设备,编码的流通常为 G711 或 8k PCM。PCM 1s 的音频 8000*16/8=16000,按照 25fps,一帧长度 16000/25=640 字节。g711 对 PCM,压缩比 2:1,需要长度 320 字节。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈