mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-21 18:35:54 +08:00
更新硬件SDK
This commit is contained in:
65
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_fs_api.h
vendored
Normal file
65
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_fs_api.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file aiot_fs_api.h
|
||||
* @brief SDK linkspeech依赖的文件操作,所有依赖的文件操作将在此列出
|
||||
* @date 2019-12-27
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2025 Alibaba Group Holding Limited
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AIOT_FS_API_H_
|
||||
#define _AIOT_FS_API_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief 用以向SDK描述其运行硬件平台的资源如何使用的方法结构体
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 查询文件大小
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval -1 文件不存在
|
||||
* @retval >=0 实际文件大小
|
||||
*/
|
||||
int32_t (*file_size)(char *path);
|
||||
/**
|
||||
* @brief 删除文件
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval 0 文件删除成功
|
||||
* @retval -1 文件修改失败
|
||||
*/
|
||||
int32_t (*file_delete)(char *path);
|
||||
/**
|
||||
* @brief 写文件数据
|
||||
*
|
||||
* @details 如果文件不存在,则创建新文件
|
||||
* @return int32_t
|
||||
* @retval 成功,返回写入的文件长度
|
||||
* @retval 失败,返回-1
|
||||
*/
|
||||
int32_t (*file_write)(char *path, uint32_t offset, uint8_t *data, uint32_t len);
|
||||
/**
|
||||
* @brief 写文件数据
|
||||
*
|
||||
* @details open操作需用户执行
|
||||
* @return int32_t
|
||||
* @retval 成功,返回读取到的文件长度
|
||||
* @retval 失败,返回-1
|
||||
*/
|
||||
int32_t (*file_read)(char *path, uint32_t offset, uint8_t *data, uint32_t len);
|
||||
} aiot_fs_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
948
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.c
vendored
Normal file
948
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.c
vendored
Normal file
@@ -0,0 +1,948 @@
|
||||
#include "aiot_linkspeech_api.h"
|
||||
#include "aiot_fs_api.h"
|
||||
#include "aiot_dm_api.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "aiot_state_api.h"
|
||||
#include <stdio.h>
|
||||
#include <cJSON.h>
|
||||
#include <string.h>
|
||||
#include "core_string.h"
|
||||
#include "http_download.h"
|
||||
#include "core_list.h"
|
||||
#include "speech_trans.h"
|
||||
#include "core_log.h"
|
||||
|
||||
#define TAG "LINKSPEECH"
|
||||
|
||||
/* 文件系统抽象接口 */
|
||||
static aiot_fs_t *fs = NULL;
|
||||
/* 操作系统抽象接口*/
|
||||
static aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
#define AIOT_LSOPT_SPEECH_BUFFER_SIZE_DEFAULT 10
|
||||
#define AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT 15
|
||||
|
||||
typedef struct {
|
||||
char *jobcode;
|
||||
char *json_url;
|
||||
struct core_list_head linked_node;
|
||||
} core_download_node_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t msg_id;
|
||||
char *rrpc_id;
|
||||
char *id;
|
||||
char *format;
|
||||
char *speechs;
|
||||
struct core_list_head play_list;
|
||||
struct core_list_head linked_node;
|
||||
} core_speech_task_t;
|
||||
|
||||
typedef struct {
|
||||
/* 物模型对象*/
|
||||
void *dm_handle;
|
||||
/* 音频播放接口 */
|
||||
player_cb_t player;
|
||||
/* 用户设置工作目录 */
|
||||
char *work_dir;
|
||||
int32_t https_enable;
|
||||
int32_t speech_buffer_size;
|
||||
|
||||
/* 以上内容为用户配置,以下为运行时状态 */
|
||||
|
||||
/* 下载任务管理 */
|
||||
void *download_mutex;
|
||||
struct core_list_head download_task_list;
|
||||
/* 播报任务管理 */
|
||||
void *speech_task_mutex;
|
||||
int32_t speech_task_num;
|
||||
struct core_list_head speech_task_list;
|
||||
/* 用于判断是否需要退出千里传音 */
|
||||
int8_t running;
|
||||
/* 正在播报的任务 */
|
||||
core_speech_task_t *playing_task;
|
||||
/* 播放音频回调参数 */
|
||||
play_param_t play_param;
|
||||
/* 防止重复播放 */
|
||||
char *dup_id[AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT];
|
||||
int8_t write_pos;
|
||||
} linkspeech_handle_t;
|
||||
|
||||
typedef struct {
|
||||
linkspeech_handle_t *linkspeech;
|
||||
char *file_name;
|
||||
} download_userdata_t;
|
||||
|
||||
static int32_t file_write(uint32_t offset, uint8_t *data, uint32_t data_len, void *userdata) {
|
||||
char *file_name = (char *)userdata;
|
||||
if(userdata == NULL || data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
core_log3(sysdep, 0, "file %s, offset %d, len %d\r\n", file_name, &offset, &data_len);
|
||||
|
||||
return fs->file_write(file_name, offset, data, data_len);
|
||||
}
|
||||
|
||||
/* 下载文件到本地文件系统 */
|
||||
static int32_t core_download_file(const char *remote_url, const char *local_url, int32_t tls) {
|
||||
http_download_params_t params;
|
||||
core_log2(sysdep, 0, "[http] remote %s, local %s\r\n", (char *)remote_url, (char *)local_url);
|
||||
|
||||
if(tls == 0) {
|
||||
return core_http_download_request((char *)remote_url, NULL, file_write, (void *)local_url);
|
||||
} else {
|
||||
memset(¶ms, 0, sizeof(http_download_params_t));
|
||||
params.https_enable = 1;
|
||||
return core_http_download_request((char *)remote_url, ¶ms, file_write, (void *)local_url);
|
||||
}
|
||||
}
|
||||
|
||||
/* 事件上报函数演示 */
|
||||
static int32_t core_send_event_post(void *dm_handle, char *event_id, char *params)
|
||||
{
|
||||
aiot_dm_msg_t msg;
|
||||
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
msg.type = AIOT_DMMSG_EVENT_POST;
|
||||
msg.data.event_post.event_id = event_id;
|
||||
msg.data.event_post.params = params;
|
||||
|
||||
return aiot_dm_send(dm_handle, &msg);
|
||||
}
|
||||
|
||||
static int32_t core_delete_speech_task(core_speech_task_t *speech_task)
|
||||
{
|
||||
play_node_t *node = NULL, *next = NULL;
|
||||
if(speech_task == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(speech_task->rrpc_id != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->rrpc_id);
|
||||
}
|
||||
|
||||
if(speech_task->id != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->id);
|
||||
}
|
||||
|
||||
if(speech_task->format != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->format);
|
||||
}
|
||||
|
||||
if(speech_task->speechs != NULL) {
|
||||
sysdep->core_sysdep_free(speech_task->speechs);
|
||||
}
|
||||
|
||||
core_list_for_each_entry_safe(node, next, &speech_task->play_list, linked_node, play_node_t) {
|
||||
core_list_del(&node->linked_node);
|
||||
if(node->filename != NULL) {
|
||||
sysdep->core_sysdep_free(node->filename);
|
||||
}
|
||||
sysdep->core_sysdep_free(node);
|
||||
}
|
||||
|
||||
sysdep->core_sysdep_free(speech_task);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 将语料信息转换为语料文件路径 */
|
||||
static int32_t core_speech_task_prepare(core_speech_task_t *speech_task)
|
||||
{
|
||||
cJSON *speechs = cJSON_Parse(speech_task->speechs);
|
||||
char *value = NULL;
|
||||
/* 如果是否json格式数据 */
|
||||
if (speechs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 将语料信息加入到播放列表中 */
|
||||
CORE_INIT_LIST_HEAD(&speech_task->play_list);
|
||||
for (int i = 0; i < cJSON_GetArraySize(speechs); i++)
|
||||
{
|
||||
value = cJSON_GetArrayItem(speechs, i)->valuestring;
|
||||
if(*value == '{' && *(value + 1)== '$') {
|
||||
money_to_speech(value + 2, speech_task->format, &speech_task->play_list);
|
||||
} else {
|
||||
name_to_speech(value, speech_task->format, &speech_task->play_list);
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(speechs);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 检查是否重复播放,如果不是重复播放,添加进查重播报列表 */
|
||||
static int32_t core_speech_duplicate_check(linkspeech_handle_t *linkspeech, core_speech_task_t *speech_task)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* 查重 */
|
||||
for(i = 0; i < AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT; i++) {
|
||||
if(linkspeech->dup_id[i] != NULL && 0 == strcmp(speech_task->id, linkspeech->dup_id[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 添加 */
|
||||
if(linkspeech->dup_id[linkspeech->write_pos] != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->dup_id[linkspeech->write_pos]);
|
||||
linkspeech->dup_id[linkspeech->write_pos] = NULL;
|
||||
}
|
||||
|
||||
core_strdup(sysdep, &linkspeech->dup_id[linkspeech->write_pos], speech_task->id, TAG);
|
||||
linkspeech->write_pos++;
|
||||
if(linkspeech->write_pos >= AIOT_SPEECH_DUPLICATE_SIZE_DEFAULT) {
|
||||
linkspeech->write_pos = 0;
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 检查语料文件是否存在 */
|
||||
static int32_t core_speech_task_file_check(linkspeech_handle_t *linkspeech, core_speech_task_t *speech_task)
|
||||
{
|
||||
play_node_t *node = NULL, *next = NULL;
|
||||
char *path = NULL;
|
||||
char *src[2] = { NULL, NULL};
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
res = core_speech_task_prepare(speech_task);
|
||||
if(res != STATE_SUCCESS ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
core_list_for_each_entry_safe(node, next, &speech_task->play_list, linked_node, play_node_t) {
|
||||
src[0] = linkspeech->work_dir;
|
||||
src[1] = node->filename;
|
||||
path = NULL;
|
||||
core_sprintf(sysdep, &path, "%s/%s", src, sizeof(src)/sizeof(char *), TAG);
|
||||
sysdep->core_sysdep_free(node->filename);
|
||||
node->filename = path;
|
||||
if(fs->file_size(node->filename) <= 0) {
|
||||
core_log1(sysdep, 0, "loss file %s\r\n", node->filename);
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t send_speech_task_result(linkspeech_handle_t *linkspeech, core_speech_task_t* speech_task, int32_t code)
|
||||
{
|
||||
aiot_dm_msg_t msg;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *data = NULL;
|
||||
char *src[] = { NULL, NULL, NULL };
|
||||
|
||||
if(linkspeech == NULL || speech_task == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(code){
|
||||
case 1:{
|
||||
src[0] = "1";
|
||||
src[1] = "duplicate speechbroad id";
|
||||
}
|
||||
break;
|
||||
case 2:{
|
||||
src[0] = "2";
|
||||
src[1] = "speechs file not found";
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
src[0] = "0";
|
||||
src[1] = "success";
|
||||
}
|
||||
break;
|
||||
}
|
||||
src[2] = speech_task->id;
|
||||
core_sprintf(sysdep, &data, "{\"result\":%s,\"error_message\":\"%s\",\"task_id\":\"%s\"}", src, sizeof(src) / sizeof(char *), TAG );
|
||||
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
if(speech_task->rrpc_id != NULL) {
|
||||
msg.type = AIOT_DMMSG_SYNC_SERVICE_REPLY;
|
||||
msg.data.sync_service_reply.rrpc_id = speech_task->rrpc_id;
|
||||
msg.data.sync_service_reply.msg_id = speech_task->msg_id;
|
||||
msg.data.sync_service_reply.service_id = "SyncSpeechBroadcast";
|
||||
msg.data.sync_service_reply.code = 200;
|
||||
msg.data.sync_service_reply.data = data;
|
||||
} else {
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
msg.type = AIOT_DMMSG_ASYNC_SERVICE_REPLY;
|
||||
msg.data.async_service_reply.msg_id = speech_task->msg_id;
|
||||
msg.data.async_service_reply.code = 200;
|
||||
msg.data.async_service_reply.service_id = "SpeechBroadcast";
|
||||
msg.data.async_service_reply.data = data;
|
||||
}
|
||||
|
||||
res = aiot_dm_send(linkspeech->dm_handle, &msg);
|
||||
sysdep->core_sysdep_free(data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static core_speech_task_t* core_speech_update_task(linkspeech_handle_t *linkspeech)
|
||||
{
|
||||
core_speech_task_t* speech_task = NULL;
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
if(core_list_empty(&linkspeech->speech_task_list)) {
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
speech_task = core_list_first_entry(&linkspeech->speech_task_list, core_speech_task_t, linked_node);
|
||||
core_list_del(&speech_task->linked_node);
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
|
||||
return speech_task;
|
||||
}
|
||||
|
||||
static int32_t core_check_play_task(linkspeech_handle_t *linkspeech)
|
||||
{
|
||||
play_node_t *node = NULL;
|
||||
|
||||
if( linkspeech->playing_task == NULL ) {
|
||||
linkspeech->playing_task = core_speech_update_task(linkspeech);
|
||||
if(linkspeech->playing_task == NULL || core_list_empty(&linkspeech->playing_task->play_list)) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* 播放完单个文件,删除 */
|
||||
node = core_list_first_entry(&linkspeech->playing_task->play_list, play_node_t, linked_node);
|
||||
core_list_del(&node->linked_node);
|
||||
sysdep->core_sysdep_free(node->filename);
|
||||
sysdep->core_sysdep_free(node);
|
||||
|
||||
/* 查询任务是否播放完成 */
|
||||
if(core_list_empty(&linkspeech->playing_task->play_list)) {
|
||||
/* 异步回复任务播放完成 */
|
||||
if(linkspeech->playing_task->rrpc_id == NULL) {
|
||||
send_speech_task_result(linkspeech, linkspeech->playing_task, 0);
|
||||
}
|
||||
/* 回收任务资源 */
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
core_list_del(&linkspeech->playing_task->linked_node);
|
||||
core_delete_speech_task(linkspeech->playing_task);
|
||||
linkspeech->speech_task_num--;
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
|
||||
/* 更新下个播报任务 */
|
||||
linkspeech->playing_task = core_speech_update_task(linkspeech);
|
||||
if(linkspeech->playing_task == NULL || core_list_empty(&linkspeech->playing_task->play_list)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( linkspeech->playing_task != NULL && linkspeech->player != NULL ) {
|
||||
node = core_list_first_entry(&linkspeech->playing_task->play_list, play_node_t, linked_node);
|
||||
linkspeech->player(node->filename, &linkspeech->play_param);
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static core_speech_task_t *core_speech_broadcast_parse(linkspeech_handle_t *linkspeech, char *data, int datalen)
|
||||
{
|
||||
cJSON *speechs = NULL, *format = NULL, *id = NULL;
|
||||
core_speech_task_t *speech_task = NULL;
|
||||
cJSON *root = cJSON_Parse(data);
|
||||
|
||||
/* 如果是否json格式数据 */
|
||||
if (root == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
speechs = cJSON_GetObjectItem(root, "speechs");
|
||||
if (speechs == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
format = cJSON_GetObjectItem(root, "format");
|
||||
if (format == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = cJSON_GetObjectItem(root, "id");
|
||||
if (id == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
speech_task = sysdep->core_sysdep_malloc(sizeof(core_speech_task_t), TAG);
|
||||
if(speech_task == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return NULL;
|
||||
}
|
||||
memset(speech_task, 0, sizeof(*speech_task));
|
||||
CORE_INIT_LIST_HEAD(&speech_task->play_list);
|
||||
|
||||
core_strdup(sysdep, &speech_task->format, format->valuestring, TAG);
|
||||
core_strdup(sysdep, &speech_task->id, id->valuestring, TAG);
|
||||
speech_task->speechs = cJSON_Print(speechs);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return speech_task;
|
||||
}
|
||||
|
||||
/* 解析语料下载任务,并执行 */
|
||||
static int32_t core_speech_download_parse(linkspeech_handle_t *linkspeech, char *data, int datalen)
|
||||
{
|
||||
char *jobcode = NULL;
|
||||
char *value = NULL;
|
||||
uint32_t value_len = 0;
|
||||
core_download_node_t *node = NULL;
|
||||
|
||||
/* 解析下载jobcode*/
|
||||
int res = core_json_value(data, datalen,
|
||||
"jobcode", strlen("jobcode"), &value, &value_len);
|
||||
if (res != STATE_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jobcode = sysdep->core_sysdep_malloc(value_len + 1, TAG);
|
||||
memcpy(jobcode, value, value_len);
|
||||
jobcode[value_len] = 0;
|
||||
|
||||
res = core_json_value(data, datalen,
|
||||
"url", strlen("url"), &value, &value_len);
|
||||
if (res != STATE_SUCCESS) {
|
||||
sysdep->core_sysdep_free(jobcode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 记录下载的url及jobcode,插入下载任务列表中 */
|
||||
node = (core_download_node_t *)sysdep->core_sysdep_malloc(sizeof(core_download_node_t), TAG);
|
||||
memset(node, 0, sizeof(*node));
|
||||
node->json_url = sysdep->core_sysdep_malloc(value_len + 1, TAG);
|
||||
memcpy(node->json_url, value, value_len);
|
||||
*(node->json_url + value_len) = 0;
|
||||
node->jobcode = jobcode;
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->download_mutex);
|
||||
core_list_add_tail(&node->linked_node, &linkspeech->download_task_list);
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->download_mutex);
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
/* 批量删除语料 */
|
||||
static int32_t core_speech_delete_parse(linkspeech_handle_t *linkspeech, char *data, uint32_t datalen)
|
||||
{
|
||||
cJSON *root = NULL, *speechs = NULL, *speech = NULL;
|
||||
cJSON *formart, *id;
|
||||
char *filename = NULL;
|
||||
char *src[3] = {NULL, NULL, NULL};
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
//如果是否json格式数据
|
||||
root = cJSON_Parse(data);
|
||||
if (root == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
speechs = cJSON_GetObjectItem(root, "speechs");
|
||||
if (speechs == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cJSON_GetArraySize(speechs); i++)
|
||||
{
|
||||
speech = cJSON_GetArrayItem(speechs, i);
|
||||
if(speech != NULL) {
|
||||
formart = cJSON_GetObjectItem(speech, "format");
|
||||
id = cJSON_GetObjectItem(speech, "id");
|
||||
src[0] = linkspeech->work_dir;
|
||||
src[1] = id->valuestring;
|
||||
src[2] = formart->valuestring;
|
||||
core_sprintf(sysdep, &filename, "%s/%s.%s", src, sizeof(src) / sizeof(char *), TAG );
|
||||
/* 存在该文件就删除 */
|
||||
if(fs->file_size(filename) > 0) {
|
||||
fs->file_delete(filename);
|
||||
}
|
||||
sysdep->core_sysdep_free(filename);
|
||||
}
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* 物模型服务调用处理 */
|
||||
static void core_dm_recv_async_service_invoke(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)userdata;
|
||||
core_speech_task_t *speech_task = NULL;
|
||||
aiot_dm_msg_t msg;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if(linkspeech == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 消息回复 */
|
||||
memset(&msg, 0, sizeof(aiot_dm_msg_t));
|
||||
msg.type = AIOT_DMMSG_ASYNC_SERVICE_REPLY;
|
||||
msg.data.async_service_reply.msg_id = recv->data.async_service_invoke.msg_id;
|
||||
msg.data.async_service_reply.code = 200;
|
||||
msg.data.async_service_reply.service_id = recv->data.async_service_invoke.service_id;
|
||||
msg.data.async_service_reply.data = "{}";
|
||||
|
||||
if(0 == strcmp(recv->data.async_service_invoke.service_id, "SpeechPost")) {
|
||||
/* 语料下发 */
|
||||
core_speech_download_parse(linkspeech, recv->data.async_service_invoke.params, recv->data.async_service_invoke.params_len);
|
||||
res = aiot_dm_send(dm_handle, &msg);
|
||||
if (res < 0) {
|
||||
core_log(sysdep, 0, "aiot_dm_send failed\r\n");
|
||||
}
|
||||
} else if(0 == strcmp(recv->data.async_service_invoke.service_id, "DeleteSpeech")) {
|
||||
/* 语料批量删除 */
|
||||
core_speech_delete_parse(linkspeech, recv->data.async_service_invoke.params, recv->data.async_service_invoke.params_len);
|
||||
res = aiot_dm_send(dm_handle, &msg);
|
||||
if (res < 0) {
|
||||
core_log(sysdep, 0, "aiot_dm_send failed\r\n");
|
||||
}
|
||||
}
|
||||
else if(0 == strcmp(recv->data.async_service_invoke.service_id, "SpeechBroadcast")) {
|
||||
if(linkspeech->speech_task_num > linkspeech->speech_buffer_size) {
|
||||
core_log2(sysdep, 0, "SpeechBroadcast task buff full [%d] > [%d]\r\n", &linkspeech->speech_task_num, &linkspeech->speech_buffer_size);
|
||||
return;
|
||||
}
|
||||
/* 语料组合播报 */
|
||||
speech_task = core_speech_broadcast_parse(linkspeech, recv->data.async_service_invoke.params, recv->data.async_service_invoke.params_len);
|
||||
if(speech_task != NULL) {
|
||||
speech_task->rrpc_id = NULL;
|
||||
speech_task->msg_id = recv->data.async_service_invoke.msg_id;
|
||||
if(STATE_SUCCESS != core_speech_duplicate_check(linkspeech, speech_task)) {
|
||||
core_log1(sysdep, 0, "SpeechBroadcast duplicate id [%s]\r\n", speech_task->id);
|
||||
send_speech_task_result(linkspeech, speech_task, 1);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else if(STATE_SUCCESS != core_speech_task_file_check(linkspeech, speech_task)){
|
||||
send_speech_task_result(linkspeech, speech_task, 2);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else {
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
core_list_add_tail(&speech_task->linked_node, &linkspeech->speech_task_list);
|
||||
linkspeech->speech_task_num++;
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
if( linkspeech->playing_task == NULL ) {
|
||||
core_check_play_task(linkspeech);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 物模型同步服务调用处理 */
|
||||
static void core_dm_recv_sync_service_invoke(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)userdata;
|
||||
core_speech_task_t *speech_task = NULL;
|
||||
|
||||
if(0 == strcmp(recv->data.sync_service_invoke.service_id, "SyncSpeechBroadcast")) {
|
||||
if(linkspeech->speech_task_num > linkspeech->speech_buffer_size) {
|
||||
core_log2(sysdep, 0, "SpeechBroadcast task buff full [%d] > [%d]\r\n", &linkspeech->speech_task_num, &linkspeech->speech_buffer_size);
|
||||
return;
|
||||
}
|
||||
/* 语料组合播报 */
|
||||
speech_task = core_speech_broadcast_parse(linkspeech, recv->data.sync_service_invoke.params, recv->data.sync_service_invoke.params_len);
|
||||
if(speech_task != NULL) {
|
||||
speech_task->rrpc_id = NULL;
|
||||
core_strdup(sysdep, &speech_task->rrpc_id, recv->data.sync_service_invoke.rrpc_id, TAG);
|
||||
speech_task->msg_id = recv->data.async_service_invoke.msg_id;
|
||||
if(STATE_SUCCESS != core_speech_duplicate_check(linkspeech, speech_task)) {
|
||||
core_log1(sysdep, 0, "SpeechBroadcast duplicate id [%s]\r\n", speech_task->id);
|
||||
send_speech_task_result(linkspeech, speech_task, 1);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else if(STATE_SUCCESS != core_speech_task_file_check(linkspeech, speech_task)){
|
||||
send_speech_task_result(linkspeech, speech_task, 2);
|
||||
core_delete_speech_task(speech_task);
|
||||
return;
|
||||
} else {
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
core_list_add_tail(&speech_task->linked_node, &linkspeech->speech_task_list);
|
||||
linkspeech->speech_task_num++;
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
/* 同步调用需要立即返回立即返回 */
|
||||
send_speech_task_result(linkspeech, speech_task, 0);
|
||||
if( linkspeech->playing_task == NULL ) {
|
||||
core_check_play_task(linkspeech);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 用户数据接收处理回调函数 */
|
||||
static void core_dm_recv_handler(void *dm_handle, const aiot_dm_recv_t *recv, void *userdata)
|
||||
{
|
||||
switch (recv->type) {
|
||||
/* 异步服务调用 */
|
||||
case AIOT_DMRECV_ASYNC_SERVICE_INVOKE: {
|
||||
core_dm_recv_async_service_invoke(dm_handle, recv, userdata);
|
||||
}
|
||||
break;
|
||||
|
||||
/* 同步服务调用 */
|
||||
case AIOT_DMRECV_SYNC_SERVICE_INVOKE: {
|
||||
core_dm_recv_sync_service_invoke(dm_handle, recv, userdata);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void core_play_finished(char *filename, void *userdata)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)userdata;
|
||||
if(linkspeech == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
core_log1(sysdep, 0, "core_play_finished file %s\r\n", filename);
|
||||
core_check_play_task(linkspeech);
|
||||
}
|
||||
|
||||
void *aiot_linkspeech_init()
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
int i = 0;
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if (NULL == sysdep) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
linkspeech = sysdep->core_sysdep_malloc(sizeof(linkspeech_handle_t), TAG);
|
||||
if(linkspeech == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(linkspeech, 0, sizeof(linkspeech_handle_t));
|
||||
/* 配置项设置为空 */
|
||||
linkspeech->dm_handle = NULL;
|
||||
linkspeech->player = NULL;
|
||||
linkspeech->work_dir = NULL;
|
||||
linkspeech->speech_buffer_size = AIOT_LSOPT_SPEECH_BUFFER_SIZE_DEFAULT;
|
||||
|
||||
/* 下载管理初始化 */
|
||||
linkspeech->download_mutex = sysdep->core_sysdep_mutex_init();
|
||||
CORE_INIT_LIST_HEAD(&linkspeech->download_task_list);
|
||||
|
||||
/* 语音播报任务初始化 */
|
||||
linkspeech->speech_task_mutex = sysdep->core_sysdep_mutex_init();
|
||||
linkspeech->speech_task_num = 0;
|
||||
CORE_INIT_LIST_HEAD(&linkspeech->speech_task_list);
|
||||
|
||||
linkspeech->play_param.on_finish = core_play_finished;
|
||||
linkspeech->play_param.userdata = linkspeech;
|
||||
linkspeech->playing_task = NULL;
|
||||
linkspeech->https_enable = 0;
|
||||
|
||||
for(i = 0; i < sizeof(linkspeech->dup_id) / sizeof(char *); i++){
|
||||
linkspeech->dup_id[i] = NULL;
|
||||
}
|
||||
linkspeech->write_pos = 0;
|
||||
|
||||
return linkspeech;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_deinit(void **handle)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
core_download_node_t *down_node = NULL, *down_next = NULL;
|
||||
core_speech_task_t *speech_node = NULL, *speech_next = NULL;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
int i = 0;
|
||||
|
||||
if (NULL == handle || NULL == *handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
linkspeech = (linkspeech_handle_t *)*handle;
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->speech_task_mutex);
|
||||
/* 删除播报任务列表 */
|
||||
core_list_for_each_entry_safe(speech_node, speech_next, &linkspeech->speech_task_list, linked_node, core_speech_task_t) {
|
||||
core_list_del(&speech_node->linked_node);
|
||||
core_delete_speech_task(speech_node);
|
||||
speech_node = NULL;
|
||||
}
|
||||
linkspeech->speech_task_num = 0;
|
||||
/* 删除正在播报的任务 */
|
||||
if(linkspeech->playing_task != NULL) {
|
||||
core_delete_speech_task(linkspeech->playing_task);
|
||||
linkspeech->playing_task = NULL;
|
||||
}
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->speech_task_mutex);
|
||||
sysdep->core_sysdep_mutex_deinit(&linkspeech->speech_task_mutex);
|
||||
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->download_mutex);
|
||||
core_list_for_each_entry_safe(down_node, down_next, &linkspeech->download_task_list, linked_node, core_download_node_t) {
|
||||
core_list_del(&down_node->linked_node);
|
||||
sysdep->core_sysdep_free(down_node->jobcode);
|
||||
sysdep->core_sysdep_free(down_node->json_url);
|
||||
sysdep->core_sysdep_free(down_node);
|
||||
}
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->download_mutex);
|
||||
sysdep->core_sysdep_mutex_deinit(&linkspeech->download_mutex);
|
||||
|
||||
if(linkspeech->work_dir != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->work_dir);
|
||||
}
|
||||
|
||||
if(linkspeech->dm_handle != NULL) {
|
||||
/* 销毁DATA-MODEL实例, 一般不会运行到这里 */
|
||||
res = aiot_dm_deinit(&linkspeech->dm_handle);
|
||||
if (res < STATE_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < sizeof(linkspeech->dup_id) / sizeof(char *); i++){
|
||||
if(linkspeech->dup_id[i] != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->dup_id[i]);
|
||||
}
|
||||
linkspeech->dup_id[i] = NULL;
|
||||
}
|
||||
linkspeech->write_pos = 0;
|
||||
|
||||
sysdep->core_sysdep_free(linkspeech);
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_setopt(void *handle, aiot_linkspeech_option_t option, void *data)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
uint8_t post_reply = 1;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle || NULL == data) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
if (option >= AIOT_LSOPT_MAX) {
|
||||
return STATE_USER_INPUT_OUT_RANGE;
|
||||
}
|
||||
|
||||
linkspeech = (linkspeech_handle_t *)handle;
|
||||
|
||||
switch(option) {
|
||||
case AIOT_LSOPT_MQTT_HANDLE: {
|
||||
if(linkspeech->dm_handle != NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* 创建DATA-MODEL实例 */
|
||||
linkspeech->dm_handle = aiot_dm_init();
|
||||
if (linkspeech->dm_handle == NULL) {
|
||||
return STATE_SYS_DEPEND_MALLOC_FAILED;
|
||||
}
|
||||
/* 配置MQTT实例句柄 */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_MQTT_HANDLE, data );
|
||||
/* 配置消息接收处理回调函数 */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_RECV_HANDLER, (void *)core_dm_recv_handler);
|
||||
/* 配置回调函数的userdata */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_USERDATA, (void *)linkspeech);
|
||||
/* 配置是云端否需要回复post_reply给设备. 如果为1, 表示需要云端回复, 否则表示不回复 */
|
||||
aiot_dm_setopt(linkspeech->dm_handle, AIOT_DMOPT_POST_REPLY, (void *)&post_reply);
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_FILE_OPS: {
|
||||
fs = (aiot_fs_t *)data;
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_PLAYER_CALLBACK: {
|
||||
linkspeech->player = (player_cb_t)data;
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_WORK_DIR: {
|
||||
if (linkspeech->work_dir != NULL) {
|
||||
sysdep->core_sysdep_free(linkspeech->work_dir);
|
||||
linkspeech->work_dir = NULL;
|
||||
}
|
||||
|
||||
core_strdup(sysdep, &linkspeech->work_dir, (char *)data, TAG);
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_HTTPS_ENABLE: {
|
||||
if(*(int32_t *)data != 0 && *(int32_t *)data != 1) {
|
||||
return -1;
|
||||
}
|
||||
linkspeech->https_enable = *(int32_t *)data;
|
||||
}
|
||||
break;
|
||||
|
||||
case AIOT_LSOPT_SPEECH_BUFFER_SIZE: {
|
||||
if(*(int32_t *)data <= 0 || *(int32_t *)data > 255) {
|
||||
return -1;
|
||||
}
|
||||
linkspeech->speech_buffer_size = *(int32_t *)data;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 语料下载url.json文件解析并下载语料 */
|
||||
static int32_t core_speech_download_file_parse(linkspeech_handle_t *linkspeech, char *data, uint32_t datalen)
|
||||
{
|
||||
cJSON *root = NULL, *audios = NULL, *audio = NULL;
|
||||
cJSON *formart, *id, *url;
|
||||
char *local_file = NULL;
|
||||
char *src[3] = {NULL, NULL, NULL};
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
//如果是否json格式数据
|
||||
root = cJSON_Parse(data);
|
||||
if (root == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
audios = cJSON_GetObjectItem(root, "audios");
|
||||
if (audios == NULL) {
|
||||
cJSON_Delete(root);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cJSON_GetArraySize(audios); i++)
|
||||
{
|
||||
audio = cJSON_GetArrayItem(audios, i);
|
||||
if(audio != NULL) {
|
||||
formart = cJSON_GetObjectItem(audio,"format");
|
||||
id = cJSON_GetObjectItem(audio,"id");
|
||||
url = cJSON_GetObjectItem(audio,"url");
|
||||
src[0] = linkspeech->work_dir;
|
||||
src[1] = id->valuestring;
|
||||
src[2] = formart->valuestring;
|
||||
core_sprintf(sysdep, &local_file, "%s/%s.%s", src, sizeof(src) / sizeof(char *), TAG );
|
||||
if(fs->file_size(local_file) > 0) {
|
||||
fs->file_delete(local_file);
|
||||
}
|
||||
res = core_download_file(url->valuestring, local_file, linkspeech->https_enable);
|
||||
if(res != STATE_SUCCESS) {
|
||||
sysdep->core_sysdep_free(local_file);
|
||||
break;
|
||||
}
|
||||
sysdep->core_sysdep_free(local_file);
|
||||
}
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_start(void *handle)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = (linkspeech_handle_t *)handle;
|
||||
char *data = NULL;
|
||||
char *response = NULL;
|
||||
char *response_src[2] = {NULL};
|
||||
char *json_file = NULL;
|
||||
char *json_file_src[2] = { NULL, NULL };
|
||||
int32_t res = STATE_SUCCESS;
|
||||
char *result_success = "0";
|
||||
char *result_error = "255";
|
||||
int32_t file_len = 0, read_len = 0;
|
||||
core_download_node_t *node = NULL;
|
||||
|
||||
if (NULL == handle || fs == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
if(linkspeech->work_dir == NULL || linkspeech->player == NULL) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
linkspeech->running = 1;
|
||||
|
||||
while(linkspeech->running) {
|
||||
/* 读取下载任务 */
|
||||
node = NULL;
|
||||
sysdep->core_sysdep_mutex_lock(linkspeech->download_mutex);
|
||||
node = core_list_first_entry(&linkspeech->download_task_list, core_download_node_t, linked_node);
|
||||
if(&node->linked_node != &linkspeech->download_task_list) {
|
||||
core_list_del(&node->linked_node);
|
||||
} else {
|
||||
node = NULL;
|
||||
}
|
||||
sysdep->core_sysdep_mutex_unlock(linkspeech->download_mutex);
|
||||
|
||||
/* 处理单个下载任务 */
|
||||
if(node != NULL) {
|
||||
/* 生成本地文件名 */
|
||||
json_file_src[0] = linkspeech->work_dir;
|
||||
json_file_src[1] = node->jobcode;
|
||||
core_sprintf(sysdep, &json_file, "%s/%s.json", json_file_src, sizeof(json_file_src) / sizeof(char *), TAG);
|
||||
|
||||
/* 下载包含语料url的json文件至本地 */
|
||||
core_download_file(node->json_url, json_file, linkspeech->https_enable);
|
||||
|
||||
/* 读取文件内容,拷贝至data */
|
||||
file_len = fs->file_size(json_file);
|
||||
data = sysdep->core_sysdep_malloc(file_len + 1, TAG);
|
||||
read_len = fs->file_read(json_file, 0, (uint8_t *)data, file_len);
|
||||
core_log3(sysdep, 0, "[%s] read_len %d, file_len %d \r\n", json_file, &read_len, &file_len);
|
||||
/* 删除不使用的记录语料地址的json文件 */
|
||||
fs->file_delete(json_file);
|
||||
sysdep->core_sysdep_free(json_file);
|
||||
|
||||
if(read_len == file_len) {
|
||||
/* 解析语料文件内容,并触发下载 */
|
||||
res = core_speech_download_file_parse(linkspeech, data, read_len);
|
||||
if(res == STATE_SUCCESS) {
|
||||
response_src[1] = result_success;
|
||||
} else {
|
||||
response_src[1] = result_error;
|
||||
}
|
||||
} else {
|
||||
response_src[1] = result_error;
|
||||
}
|
||||
|
||||
/* 删除文件相关内容 */
|
||||
sysdep->core_sysdep_free(data);
|
||||
|
||||
/* 回复云端下载完成 */
|
||||
response_src[0] = node->jobcode;
|
||||
core_sprintf(sysdep, &response, "{\"jobcode\":\"%s\", \"result\":%s}", response_src, sizeof(response_src) / sizeof(char *), TAG);
|
||||
core_send_event_post(linkspeech->dm_handle, "SpeechUpdateResponse", response);
|
||||
sysdep->core_sysdep_free(response);
|
||||
|
||||
/* 删除下载任务节点 */
|
||||
sysdep->core_sysdep_free(node->json_url);
|
||||
sysdep->core_sysdep_free(node->jobcode);
|
||||
sysdep->core_sysdep_free(node);
|
||||
} else {
|
||||
sysdep->core_sysdep_sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t aiot_linkspeech_stop(void *handle)
|
||||
{
|
||||
linkspeech_handle_t *linkspeech = NULL;
|
||||
int32_t res = STATE_SUCCESS;
|
||||
|
||||
if (NULL == handle) {
|
||||
return STATE_USER_INPUT_NULL_POINTER;
|
||||
}
|
||||
|
||||
linkspeech = (linkspeech_handle_t *)handle;
|
||||
linkspeech->running = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
161
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.h
vendored
Normal file
161
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/aiot_linkspeech_api.h
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @file aiot_linkspeech_api.h
|
||||
* @brief LinkSpeech模块头文件, 提供设备千里传音的能力
|
||||
* @date 2019-12-27
|
||||
*
|
||||
* @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited
|
||||
*
|
||||
* @details
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AIOT_LINKSPEECH_API_H__
|
||||
#define __AIOT_LINKSPEECH_API_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
/* 当音频播报结束后执行该回调, 需要带userdata */
|
||||
void (*on_finish)(char *filename, void *userdata);
|
||||
void *userdata;
|
||||
} play_param_t;
|
||||
|
||||
/* 设置音频播放回调,该接口不能长时间阻塞 */
|
||||
typedef int32_t (*player_cb_t)(char *filename, play_param_t *ext_params);
|
||||
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief 模块依赖的MQTT句柄
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 千里传音模块依赖底层的MQTT模块, 用户必需配置正确的MQTT句柄, 否则无法正常工作
|
||||
*
|
||||
* 数据类型: (void *)
|
||||
*/
|
||||
AIOT_LSOPT_MQTT_HANDLE,
|
||||
/**
|
||||
* @brief 模块依赖的文件系统操作
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 千里传音模块依赖文件系统接口,需要用户实现并设置
|
||||
*
|
||||
* 数据类型: (aiot_fs_t *)
|
||||
*/
|
||||
AIOT_LSOPT_FILE_OPS,
|
||||
/**
|
||||
* @brief 模块依赖的语音播放的接口设置
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 千里传音模块依赖音频播放接口
|
||||
*
|
||||
* 数据类型: (player_cb_t *)
|
||||
*/
|
||||
AIOT_LSOPT_PLAYER_CALLBACK,
|
||||
/**
|
||||
* @brief 设置千里传音文件保存的文件夹路径
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (char *)
|
||||
*/
|
||||
AIOT_LSOPT_WORK_DIR,
|
||||
/**
|
||||
* @brief 是否使能https下载,默认为http下载
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 数据类型: (int32_t *) 0:http下载 1:https下载
|
||||
*/
|
||||
AIOT_LSOPT_HTTPS_ENABLE,
|
||||
/**
|
||||
* @brief 组合播报任务大缓存个数
|
||||
*
|
||||
* @details
|
||||
* 当组合播报的速度小于下发的速度时,SDK会缓存播报任务,该参数用于设置缓存播报任务的个数
|
||||
*
|
||||
* 数据类型: (int32_t *) 1~255, 默认为10
|
||||
*/
|
||||
AIOT_LSOPT_SPEECH_BUFFER_SIZE,
|
||||
|
||||
AIOT_LSOPT_MAX,
|
||||
} aiot_linkspeech_option_t;
|
||||
|
||||
/**
|
||||
* @brief 创建一个LinkSpeech实例
|
||||
*
|
||||
* @return void*
|
||||
* @retval 非NULL linkspeech实例句柄
|
||||
* @retval NULL 初始化失败, 或者是因为没有设置portfile, 或者是内存分配失败导致
|
||||
*
|
||||
*/
|
||||
void *aiot_linkspeech_init();
|
||||
|
||||
/**
|
||||
* @brief 销毁LinkSpeech实例句柄
|
||||
*
|
||||
* @param[in] handle 指向linkspeech实例句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_deinit(void **handle);
|
||||
|
||||
/**
|
||||
* @brief 设置LinkSpeech句柄的参数
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* 对LinkSpeech会话进行配置, 常见的配置选项包括
|
||||
*
|
||||
* + `AIOT_LSOPT_MQTT_HANDLE`: 把 @ref aiot_mqtt_init 返回的MQTT会话句柄跟OTA会话关联起来
|
||||
* + `AIOT_LSOPT_RECV_HANDLER`: 设置OTA消息的数据处理回调, 这个用户回调在有OTA消息的时候, 会被 @ref aiot_mqtt_recv 调用到
|
||||
*
|
||||
* @param[in] handle linkspeech句柄
|
||||
* @param[in] option 配置选项, 更多信息请参考@ref aiot_linkspeech_option_t
|
||||
* @param[in] data 配置选项数据, 更多信息请参考@ref aiot_linkspeech_option_t
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_USER_INPUT_UNKNOWN_OPTION option不支持
|
||||
* @retval STATE_SUCCESS 参数设置成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_setopt(void *handle, aiot_linkspeech_option_t option, void *data);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 启动linkspeech(千里传音)服务,会一直阻塞
|
||||
*
|
||||
* @param[in] handle 指向linkspeech实例句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_start(void *handle);
|
||||
|
||||
/**
|
||||
* @brief 关闭linkspeech(千里传音)服务,执行后aiot_linkspeech_start会退出
|
||||
*
|
||||
* @param[in] handle 指向linkspeech实例句柄的指针
|
||||
*
|
||||
* @return int32_t
|
||||
* @retval STATE_SUCCESS 执行成功
|
||||
*
|
||||
*/
|
||||
int32_t aiot_linkspeech_stop(void *handle);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef __AIOT_LINKSPEECH_API_H__ */
|
||||
|
||||
400
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.c
vendored
Normal file
400
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.c
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
#include <stdio.h>
|
||||
#include "http_download.h"
|
||||
#include "aiot_state_api.h"
|
||||
#include "core_http.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
|
||||
#define HTTP_DOWNLOAD_HOST_MAX_LEN 512
|
||||
#define HTTP_DOWNLOAD_PATH_MAX_LEN 512
|
||||
#define HTTP_DOWNLOAD_DEFAULT_TLS_PORT 80
|
||||
#define HTTP_DOWNLOAD_BUFFER_LEN (2 * 1024)
|
||||
#define HTTP_DOWNLOAD_RECV_TIMEOUT_MS (5 * 1000)
|
||||
|
||||
#define HTTP_DOWNLOAD_HTTPCLIENT_MAX_URL_LEN (256)
|
||||
#define HTTP_DOWNLOAD_MAX_DIGIT_NUM_OF_UINT32 (20)
|
||||
#define HTTP_DOWNLOAD_RESPONSE_PARTIAL (206)
|
||||
#define HTTP_DOWNLOAD_RESPONSE_OK (200)
|
||||
|
||||
static const uint64_t crc64_table[256] = {
|
||||
0x0000000000000000, 0xb32e4cbe03a75f6f, 0xf4843657a840a05b, 0x47aa7ae9abe7ff34,
|
||||
0x7bd0c384ff8f5e33, 0xc8fe8f3afc28015c, 0x8f54f5d357cffe68, 0x3c7ab96d5468a107,
|
||||
0xf7a18709ff1ebc66, 0x448fcbb7fcb9e309, 0x0325b15e575e1c3d, 0xb00bfde054f94352,
|
||||
0x8c71448d0091e255, 0x3f5f08330336bd3a, 0x78f572daa8d1420e, 0xcbdb3e64ab761d61,
|
||||
0x7d9ba13851336649, 0xceb5ed8652943926, 0x891f976ff973c612, 0x3a31dbd1fad4997d,
|
||||
0x064b62bcaebc387a, 0xb5652e02ad1b6715, 0xf2cf54eb06fc9821, 0x41e11855055bc74e,
|
||||
0x8a3a2631ae2dda2f, 0x39146a8fad8a8540, 0x7ebe1066066d7a74, 0xcd905cd805ca251b,
|
||||
0xf1eae5b551a2841c, 0x42c4a90b5205db73, 0x056ed3e2f9e22447, 0xb6409f5cfa457b28,
|
||||
0xfb374270a266cc92, 0x48190ecea1c193fd, 0x0fb374270a266cc9, 0xbc9d3899098133a6,
|
||||
0x80e781f45de992a1, 0x33c9cd4a5e4ecdce, 0x7463b7a3f5a932fa, 0xc74dfb1df60e6d95,
|
||||
0x0c96c5795d7870f4, 0xbfb889c75edf2f9b, 0xf812f32ef538d0af, 0x4b3cbf90f69f8fc0,
|
||||
0x774606fda2f72ec7, 0xc4684a43a15071a8, 0x83c230aa0ab78e9c, 0x30ec7c140910d1f3,
|
||||
0x86ace348f355aadb, 0x3582aff6f0f2f5b4, 0x7228d51f5b150a80, 0xc10699a158b255ef,
|
||||
0xfd7c20cc0cdaf4e8, 0x4e526c720f7dab87, 0x09f8169ba49a54b3, 0xbad65a25a73d0bdc,
|
||||
0x710d64410c4b16bd, 0xc22328ff0fec49d2, 0x85895216a40bb6e6, 0x36a71ea8a7ace989,
|
||||
0x0adda7c5f3c4488e, 0xb9f3eb7bf06317e1, 0xfe5991925b84e8d5, 0x4d77dd2c5823b7ba,
|
||||
0x64b62bcaebc387a1, 0xd7986774e864d8ce, 0x90321d9d438327fa, 0x231c512340247895,
|
||||
0x1f66e84e144cd992, 0xac48a4f017eb86fd, 0xebe2de19bc0c79c9, 0x58cc92a7bfab26a6,
|
||||
0x9317acc314dd3bc7, 0x2039e07d177a64a8, 0x67939a94bc9d9b9c, 0xd4bdd62abf3ac4f3,
|
||||
0xe8c76f47eb5265f4, 0x5be923f9e8f53a9b, 0x1c4359104312c5af, 0xaf6d15ae40b59ac0,
|
||||
0x192d8af2baf0e1e8, 0xaa03c64cb957be87, 0xeda9bca512b041b3, 0x5e87f01b11171edc,
|
||||
0x62fd4976457fbfdb, 0xd1d305c846d8e0b4, 0x96797f21ed3f1f80, 0x2557339fee9840ef,
|
||||
0xee8c0dfb45ee5d8e, 0x5da24145464902e1, 0x1a083bacedaefdd5, 0xa9267712ee09a2ba,
|
||||
0x955cce7fba6103bd, 0x267282c1b9c65cd2, 0x61d8f8281221a3e6, 0xd2f6b4961186fc89,
|
||||
0x9f8169ba49a54b33, 0x2caf25044a02145c, 0x6b055fede1e5eb68, 0xd82b1353e242b407,
|
||||
0xe451aa3eb62a1500, 0x577fe680b58d4a6f, 0x10d59c691e6ab55b, 0xa3fbd0d71dcdea34,
|
||||
0x6820eeb3b6bbf755, 0xdb0ea20db51ca83a, 0x9ca4d8e41efb570e, 0x2f8a945a1d5c0861,
|
||||
0x13f02d374934a966, 0xa0de61894a93f609, 0xe7741b60e174093d, 0x545a57dee2d35652,
|
||||
0xe21ac88218962d7a, 0x5134843c1b317215, 0x169efed5b0d68d21, 0xa5b0b26bb371d24e,
|
||||
0x99ca0b06e7197349, 0x2ae447b8e4be2c26, 0x6d4e3d514f59d312, 0xde6071ef4cfe8c7d,
|
||||
0x15bb4f8be788911c, 0xa6950335e42fce73, 0xe13f79dc4fc83147, 0x521135624c6f6e28,
|
||||
0x6e6b8c0f1807cf2f, 0xdd45c0b11ba09040, 0x9aefba58b0476f74, 0x29c1f6e6b3e0301b,
|
||||
0xc96c5795d7870f42, 0x7a421b2bd420502d, 0x3de861c27fc7af19, 0x8ec62d7c7c60f076,
|
||||
0xb2bc941128085171, 0x0192d8af2baf0e1e, 0x4638a2468048f12a, 0xf516eef883efae45,
|
||||
0x3ecdd09c2899b324, 0x8de39c222b3eec4b, 0xca49e6cb80d9137f, 0x7967aa75837e4c10,
|
||||
0x451d1318d716ed17, 0xf6335fa6d4b1b278, 0xb199254f7f564d4c, 0x02b769f17cf11223,
|
||||
0xb4f7f6ad86b4690b, 0x07d9ba1385133664, 0x4073c0fa2ef4c950, 0xf35d8c442d53963f,
|
||||
0xcf273529793b3738, 0x7c0979977a9c6857, 0x3ba3037ed17b9763, 0x888d4fc0d2dcc80c,
|
||||
0x435671a479aad56d, 0xf0783d1a7a0d8a02, 0xb7d247f3d1ea7536, 0x04fc0b4dd24d2a59,
|
||||
0x3886b22086258b5e, 0x8ba8fe9e8582d431, 0xcc0284772e652b05, 0x7f2cc8c92dc2746a,
|
||||
0x325b15e575e1c3d0, 0x8175595b76469cbf, 0xc6df23b2dda1638b, 0x75f16f0cde063ce4,
|
||||
0x498bd6618a6e9de3, 0xfaa59adf89c9c28c, 0xbd0fe036222e3db8, 0x0e21ac88218962d7,
|
||||
0xc5fa92ec8aff7fb6, 0x76d4de52895820d9, 0x317ea4bb22bfdfed, 0x8250e80521188082,
|
||||
0xbe2a516875702185, 0x0d041dd676d77eea, 0x4aae673fdd3081de, 0xf9802b81de97deb1,
|
||||
0x4fc0b4dd24d2a599, 0xfceef8632775faf6, 0xbb44828a8c9205c2, 0x086ace348f355aad,
|
||||
0x34107759db5dfbaa, 0x873e3be7d8faa4c5, 0xc094410e731d5bf1, 0x73ba0db070ba049e,
|
||||
0xb86133d4dbcc19ff, 0x0b4f7f6ad86b4690, 0x4ce50583738cb9a4, 0xffcb493d702be6cb,
|
||||
0xc3b1f050244347cc, 0x709fbcee27e418a3, 0x3735c6078c03e797, 0x841b8ab98fa4b8f8,
|
||||
0xadda7c5f3c4488e3, 0x1ef430e13fe3d78c, 0x595e4a08940428b8, 0xea7006b697a377d7,
|
||||
0xd60abfdbc3cbd6d0, 0x6524f365c06c89bf, 0x228e898c6b8b768b, 0x91a0c532682c29e4,
|
||||
0x5a7bfb56c35a3485, 0xe955b7e8c0fd6bea, 0xaeffcd016b1a94de, 0x1dd181bf68bdcbb1,
|
||||
0x21ab38d23cd56ab6, 0x9285746c3f7235d9, 0xd52f0e859495caed, 0x6601423b97329582,
|
||||
0xd041dd676d77eeaa, 0x636f91d96ed0b1c5, 0x24c5eb30c5374ef1, 0x97eba78ec690119e,
|
||||
0xab911ee392f8b099, 0x18bf525d915feff6, 0x5f1528b43ab810c2, 0xec3b640a391f4fad,
|
||||
0x27e05a6e926952cc, 0x94ce16d091ce0da3, 0xd3646c393a29f297, 0x604a2087398eadf8,
|
||||
0x5c3099ea6de60cff, 0xef1ed5546e415390, 0xa8b4afbdc5a6aca4, 0x1b9ae303c601f3cb,
|
||||
0x56ed3e2f9e224471, 0xe5c372919d851b1e, 0xa26908783662e42a, 0x114744c635c5bb45,
|
||||
0x2d3dfdab61ad1a42, 0x9e13b115620a452d, 0xd9b9cbfcc9edba19, 0x6a978742ca4ae576,
|
||||
0xa14cb926613cf817, 0x1262f598629ba778, 0x55c88f71c97c584c, 0xe6e6c3cfcadb0723,
|
||||
0xda9c7aa29eb3a624, 0x69b2361c9d14f94b, 0x2e184cf536f3067f, 0x9d36004b35545910,
|
||||
0x2b769f17cf112238, 0x9858d3a9ccb67d57, 0xdff2a94067518263, 0x6cdce5fe64f6dd0c,
|
||||
0x50a65c93309e7c0b, 0xe388102d33392364, 0xa4226ac498dedc50, 0x170c267a9b79833f,
|
||||
0xdcd7181e300f9e5e, 0x6ff954a033a8c131, 0x28532e49984f3e05, 0x9b7d62f79be8616a,
|
||||
0xa707db9acf80c06d, 0x14299724cc279f02, 0x5383edcd67c06036, 0xe0ada17364673f59
|
||||
};
|
||||
|
||||
|
||||
uint64_t crc64_update(uint64_t crc, const unsigned char *s, uint64_t l) {
|
||||
|
||||
crc = ~crc;
|
||||
while (l != 0) {
|
||||
crc = crc64_table[*s++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--l;
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char host[HTTP_DOWNLOAD_HOST_MAX_LEN];
|
||||
char path[HTTP_DOWNLOAD_PATH_MAX_LEN];
|
||||
uint16_t port;
|
||||
file_save_func_t save_func;
|
||||
void *userdata;
|
||||
uint32_t range_start;
|
||||
uint32_t range_end;
|
||||
int32_t https_enable;
|
||||
|
||||
|
||||
/* 运行时参数 */
|
||||
void *http_handle;
|
||||
uint32_t size_fetched;
|
||||
uint32_t content_len;
|
||||
int32_t http_rsp_status_code;
|
||||
int32_t result;
|
||||
uint64_t content_crc64;
|
||||
uint64_t calc_crc64;
|
||||
} http_download_t;
|
||||
|
||||
/* 位于external/ali_ca_cert.c中的服务器证书 */
|
||||
extern const char *ali_ca_cert;
|
||||
extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile;
|
||||
|
||||
/* 解析URL, 从中解出来host, path */
|
||||
static int32_t _download_parse_url(const char *url, char *host, uint32_t max_host_len, char *path,
|
||||
uint32_t max_path_len)
|
||||
{
|
||||
char *host_ptr = (char *) strstr(url, "://");
|
||||
uint32_t host_len = 0;
|
||||
uint32_t path_len;
|
||||
char *path_ptr;
|
||||
char *fragment_ptr;
|
||||
|
||||
if (host_ptr == NULL) {
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
host_ptr += 3;
|
||||
|
||||
path_ptr = strchr(host_ptr, '/');
|
||||
if (NULL == path_ptr) {
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
|
||||
if (host_len == 0) {
|
||||
host_len = path_ptr - host_ptr;
|
||||
}
|
||||
|
||||
memcpy(host, host_ptr, host_len);
|
||||
host[host_len] = '\0';
|
||||
fragment_ptr = strchr(host_ptr, '#');
|
||||
if (fragment_ptr != NULL) {
|
||||
path_len = fragment_ptr - path_ptr;
|
||||
} else {
|
||||
path_len = strlen(path_ptr);
|
||||
}
|
||||
|
||||
memcpy(path, path_ptr, path_len);
|
||||
path[path_len] = '\0';
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
|
||||
static http_download_t *_http_download_init()
|
||||
{
|
||||
http_download_t *download = g_aiot_sysdep_portfile.core_sysdep_malloc(sizeof(http_download_t), "");
|
||||
if(download == NULL) {
|
||||
return download;
|
||||
}
|
||||
|
||||
memset(download, 0, sizeof(http_download_t));
|
||||
download->port = HTTP_DOWNLOAD_DEFAULT_TLS_PORT;
|
||||
download->result = STATE_SUCCESS;
|
||||
download->https_enable = 0;
|
||||
|
||||
return download;
|
||||
}
|
||||
|
||||
static void _http_download_deinit(http_download_t *download)
|
||||
{
|
||||
if(download->http_handle != NULL) {
|
||||
core_http_deinit(&download->http_handle);
|
||||
}
|
||||
g_aiot_sysdep_portfile.core_sysdep_free(download);
|
||||
}
|
||||
/* 对于收到的http报文进行处理的回调函数, 内部处理完后再调用用户的回调函数 */
|
||||
void _http_download_recv_handler(void *handle, const aiot_http_recv_t *packet, void *userdata)
|
||||
{
|
||||
http_download_t *download = (http_download_t *)userdata;
|
||||
if (NULL == download || NULL == packet) {
|
||||
return;
|
||||
}
|
||||
switch (packet->type) {
|
||||
case AIOT_HTTPRECV_STATUS_CODE : {
|
||||
download->http_rsp_status_code = packet->data.status_code.code;
|
||||
}
|
||||
break;
|
||||
case AIOT_HTTPRECV_HEADER: {
|
||||
if ((strlen(packet->data.header.key) == strlen("Content-Length")) &&
|
||||
(memcmp(packet->data.header.key, "Content-Length", strlen(packet->data.header.key)) == 0)) {
|
||||
uint32_t size = 0;
|
||||
|
||||
/* 在用户指定的range并非全部固件的情况下, content_len < size_total, 所以不能简单替换 */
|
||||
core_str2uint(packet->data.header.value, (uint8_t)strlen(packet->data.header.value), &size);
|
||||
|
||||
/* 该字段表示用户期望总共下载多少字节. 如果字段为0, 表示未设置过, 则设置为总共的字节数 */
|
||||
download->content_len = (download->content_len > 0) ? download->content_len : size;
|
||||
}
|
||||
|
||||
/* 只有整个文件下载触发校验 */
|
||||
if(download->range_start == 0 && download->range_end == 0) {
|
||||
if ((strlen(packet->data.header.key) == strlen("x-oss-hash-crc64ecma")) &&
|
||||
(memcmp(packet->data.header.key, "x-oss-hash-crc64ecma", strlen(packet->data.header.key)) == 0)) {
|
||||
core_str2uint64(packet->data.header.value, (uint8_t)strlen(packet->data.header.value), &download->content_crc64);
|
||||
download->calc_crc64 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AIOT_HTTPRECV_BODY: {
|
||||
if (HTTP_DOWNLOAD_RESPONSE_OK != download->http_rsp_status_code
|
||||
/* HTTP回复报文的code应该是200或者206, 否则这个下载链接不可用 */
|
||||
&& HTTP_DOWNLOAD_RESPONSE_PARTIAL != download->http_rsp_status_code) {
|
||||
download->result = HTTP_DOWNLOAD_ERR_FETCH_FAILED;
|
||||
core_log(NULL, 0, "wrong http respond code\r\n");
|
||||
} else if (0 == download->content_len) {
|
||||
/* HTTP回复报文的header里面应该有Content-Length, 否则这个下载链接为trunked编码, 不可用 */
|
||||
download->result = HTTP_DOWNLOAD_ERR_FETCH_FAILED;
|
||||
core_log(NULL, 0, "wrong http respond header\r\n");
|
||||
} else {
|
||||
/* 正常的固件的报文 */
|
||||
/* 在按照多个range分片下载的情况下, 判断用户下载到的固件的累计大小是否超过了整体的值 */
|
||||
if (download->size_fetched > download->content_len) {
|
||||
core_log(NULL, 0, "downloaded exceeds expected\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(download->result >= 0) {
|
||||
int32_t offset = download->size_fetched + download->range_start;
|
||||
download->save_func(offset, packet->data.body.buffer, packet->data.body.len, download->userdata);
|
||||
}
|
||||
|
||||
/* 该字段表示累计下载了多少字节, 不区分range */
|
||||
download->size_fetched += packet->data.body.len;
|
||||
|
||||
/* 计算digest, 如果下载完成, 还要看看是否与云端计算出来的一致 */
|
||||
download->calc_crc64 = crc64_update(download->calc_crc64, packet->data.body.buffer, packet->data.body.len);
|
||||
if (download->size_fetched == download->content_len) {
|
||||
/* 不需要校验或者校验成功 */
|
||||
if(download->content_crc64 == 0) {
|
||||
/* 不需要校验 */
|
||||
download->result = STATE_SUCCESS;
|
||||
}
|
||||
else if(download->content_crc64 == download->calc_crc64) {
|
||||
download->result = STATE_SUCCESS;
|
||||
core_log(NULL, 0, "crc64 matched\r\n");
|
||||
} else {
|
||||
download->result = HTTP_DOWNLOAD_ERR_CHECKSUM_MISMATCH;
|
||||
core_log(NULL, 0, "crc64 mismatch\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t _http_download_connect(http_download_t *download)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
uint32_t default_body_max_len = HTTP_DOWNLOAD_BUFFER_LEN;
|
||||
uint32_t default_timeout_ms = HTTP_DOWNLOAD_RECV_TIMEOUT_MS;
|
||||
void *http_handle = core_http_init();
|
||||
if(http_handle == NULL) {
|
||||
return STATE_PORT_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
aiot_sysdep_network_cred_t cred;
|
||||
memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
|
||||
if(download->https_enable == 0) {
|
||||
download->port = 80;
|
||||
} else {
|
||||
download->port = 443;
|
||||
cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; /* 使用RSA证书校验MQTT服务端 */
|
||||
cred.max_tls_fragment = 16384; /* 最大的分片长度为16K, 其它可选值还有4K, 2K, 1K, 0.5K */
|
||||
cred.sni_enabled = 1; /* TLS建连时, 支持Server Name Indicator */
|
||||
cred.x509_server_cert = ali_ca_cert; /* 用来验证MQTT服务端的RSA根证书 */
|
||||
cred.x509_server_cert_len = strlen(ali_ca_cert); /* 用来验证MQTT服务端的RSA根证书长度 */
|
||||
}
|
||||
|
||||
if ((STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_RECV_HANDLER, _http_download_recv_handler)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_USERDATA, (void *)download)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_BODY_BUFFER_MAX_LEN, (void *)&default_body_max_len)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_NETWORK_CRED, (void *)&cred)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_HOST, (void *)download->host)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_PORT, (void *)&download->port)) ||
|
||||
(STATE_SUCCESS != core_http_setopt(http_handle, CORE_HTTPOPT_RECV_TIMEOUT_MS, (void *)&default_timeout_ms))) {
|
||||
core_http_deinit(&http_handle);
|
||||
return STATE_PORT_MALLOC_FAILED;
|
||||
}
|
||||
|
||||
res = core_http_connect(http_handle);
|
||||
if (res != STATE_SUCCESS) {
|
||||
core_http_deinit(&http_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
download->http_handle = http_handle;
|
||||
return res;
|
||||
}
|
||||
static char header[1024];
|
||||
static int32_t _http_download_send_request(http_download_t *download)
|
||||
{
|
||||
int32_t pos = 0;
|
||||
core_http_request_t request = {
|
||||
.method = "GET",
|
||||
.path = download->path,
|
||||
.header = header,
|
||||
.content = NULL,
|
||||
.content_len = 0
|
||||
};
|
||||
|
||||
memset(header, 0, sizeof(header));
|
||||
pos += sprintf(header + pos, "Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8\r\n");
|
||||
if(download->range_end != 0) {
|
||||
pos += sprintf(header + pos, "Range: bytes=%d-%d\r\n", download->range_start, download->range_end);
|
||||
} else {
|
||||
pos += sprintf(header + pos, "Range: bytes=%d-\r\n", download->range_start);
|
||||
}
|
||||
if(pos < 0) {
|
||||
return HTTP_DOWNLOAD_ERR_UNKOWN;
|
||||
}
|
||||
|
||||
return core_http_send(download->http_handle, &request);
|
||||
}
|
||||
|
||||
static int32_t _http_download_recv(http_download_t *download)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
while(1) {
|
||||
res = core_http_recv(download->http_handle);
|
||||
if(res < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(res == STATE_HTTP_READ_BODY_FINISHED) {
|
||||
res = STATE_SUCCESS;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t core_http_download_request(char *url, http_download_params_t *extra_params, file_save_func_t save_func, void* userdata)
|
||||
{
|
||||
int32_t res = STATE_SUCCESS;
|
||||
http_download_t *download = NULL;
|
||||
|
||||
if(url == NULL || save_func == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
download = _http_download_init();
|
||||
if(download == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = _download_parse_url(url, download->host, HTTP_DOWNLOAD_HOST_MAX_LEN, download->path,
|
||||
HTTP_DOWNLOAD_PATH_MAX_LEN);
|
||||
if (res != STATE_SUCCESS) {
|
||||
_http_download_deinit(download);
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
|
||||
if(extra_params != NULL) {
|
||||
download->range_start = extra_params->range_start;
|
||||
download->range_end = extra_params->range_end;
|
||||
download->https_enable = extra_params->https_enable;
|
||||
}
|
||||
download->save_func = save_func;
|
||||
download->userdata = userdata;
|
||||
|
||||
/* 建立连接 */
|
||||
res = _http_download_connect(download);
|
||||
if(res < STATE_SUCCESS) {
|
||||
_http_download_deinit(download);
|
||||
return HTTP_DOWNLOAD_ERR_URL_INVALID;
|
||||
}
|
||||
|
||||
/* 发送请求 */
|
||||
res = _http_download_send_request(download);
|
||||
if(res != STATE_SUCCESS) {
|
||||
_http_download_deinit(download);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 接收数据 */
|
||||
res = _http_download_recv(download);
|
||||
res = download->result;
|
||||
|
||||
_http_download_deinit(download);
|
||||
return res;
|
||||
}
|
||||
54
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.h
vendored
Normal file
54
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/http_download.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef _HTTP_DOWNLOAD_H_
|
||||
#define _HTTP_DOWNLOAD_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define HTTP_DOWNLOAD_ERR_URL_INVALID -0x8001
|
||||
#define HTTP_DOWNLOAD_ERR_UNKOWN -0x8002
|
||||
#define HTTP_DOWNLOAD_ERR_FETCH_FAILED -0x8003
|
||||
#define HTTP_DOWNLOAD_ERR_CHECKSUM_MISMATCH -0x8004
|
||||
|
||||
/**
|
||||
* @brief 文件下载的额外参数
|
||||
*/
|
||||
typedef struct {
|
||||
/* 文件区间下载,起始偏移地址, 默认为0 */
|
||||
uint32_t range_start;
|
||||
/* 文件区间下载,终止偏移地址,如若不设置,置为0即可 */
|
||||
uint32_t range_end;
|
||||
/* 1: 使用https下载 0:使用http下载,默认为0 */
|
||||
int32_t https_enable;
|
||||
} http_download_params_t;
|
||||
|
||||
/**
|
||||
* @brief 文件数据保存回调函数类型定义
|
||||
* @details
|
||||
* 文件正常保存时,返回写入的数据长度
|
||||
* 文件保存异常时,返回-1, 会中断下载流程
|
||||
*/
|
||||
typedef int32_t (*file_save_func_t)(uint32_t offset, uint8_t *data, uint32_t data_len, void *userdata);
|
||||
|
||||
|
||||
/**
|
||||
* @brief http下载文件
|
||||
*
|
||||
* @param[in] url 文件下载地址
|
||||
* @param[in] extra_params 其它扩展参数,没有时可填NULL
|
||||
* @param[in] save_func 文件数据保存回调函数
|
||||
* @param[in] userdata 执行回调时返回的用户指针
|
||||
*
|
||||
* @return http_download_result_t
|
||||
* @retval <HTTP_DOWNLOAD_SUCCESS 执行失败
|
||||
* @retval HTTP_DOWNLOAD_SUCCESS 执行成功
|
||||
*/
|
||||
int32_t core_http_download_request(char *url, http_download_params_t *extra_params, file_save_func_t save_func, void* userdata);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _CORE_HTTP_H_ */
|
||||
166
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.c
vendored
Normal file
166
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.c
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "speech_trans.h"
|
||||
#include "aiot_sysdep_api.h"
|
||||
#include "core_string.h"
|
||||
|
||||
/* 系统默认的数字语音路径 */
|
||||
static const char *sys_tone_number[] = {
|
||||
"SYS_TONE_0",
|
||||
"SYS_TONE_1",
|
||||
"SYS_TONE_2",
|
||||
"SYS_TONE_3",
|
||||
"SYS_TONE_4",
|
||||
"SYS_TONE_5",
|
||||
"SYS_TONE_6",
|
||||
"SYS_TONE_7",
|
||||
"SYS_TONE_8",
|
||||
"SYS_TONE_9",
|
||||
};
|
||||
|
||||
/* 系统默认的单元路径*/
|
||||
static const char *sys_tone_measure[] = {
|
||||
"SYS_TONE_MONETARY_fen",
|
||||
"SYS_TONE_MONETARY_jiao",
|
||||
"SYS_TONE_MONETARY_yuan",
|
||||
"SYS_TONE_MEASURE_WORD_shi",
|
||||
"SYS_TONE_MEASURE_WORD_bai",
|
||||
"SYS_TONE_MEASURE_WORD_qian",
|
||||
"SYS_TONE_MEASURE_WORD_wan",
|
||||
"SYS_TONE_MEASURE_WORD_yi",
|
||||
};
|
||||
|
||||
/* 语料名字转换成文件添加进链表 */
|
||||
void name_to_speech(const char *value, char *format, struct core_list_head *list)
|
||||
{
|
||||
aiot_sysdep_portfile_t *sysdep = NULL;
|
||||
play_node_t *node = NULL;
|
||||
char *src[] = { (char *)value, format };
|
||||
sysdep = aiot_sysdep_get_portfile();
|
||||
if(sysdep == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
node = sysdep->core_sysdep_malloc(sizeof(play_node_t), "");
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(node, 0, sizeof(play_node_t));
|
||||
CORE_INIT_LIST_HEAD(&node->linked_node);
|
||||
|
||||
core_sprintf(sysdep, &node->filename, "%s.%s", src, sizeof(src) / sizeof(char *), "");
|
||||
if (node->filename == NULL) {
|
||||
sysdep->core_sysdep_free(node);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("add name %s\r\n", node->filename);
|
||||
core_list_add_tail(&node->linked_node, list);
|
||||
}
|
||||
|
||||
/* 转换整形数字 */
|
||||
void play_integer_number(uint64_t integer, char *format, struct core_list_head *list)
|
||||
{
|
||||
uint64_t quotient = 0, remain = 0;
|
||||
if(integer >= 100000000ul) {
|
||||
quotient = integer / 100000000ul;
|
||||
remain = integer % 100000000ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[7], format, list);
|
||||
if(remain > 0 && 100000000ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 10000ul) {
|
||||
quotient = integer / 10000ul;
|
||||
remain = integer % 10000ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[6], format, list);
|
||||
if(remain > 0 && 10000ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 1000ul) {
|
||||
quotient = integer / 1000ul;
|
||||
remain = integer % 1000ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[5], format, list);
|
||||
if(remain > 0 && 1000ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 100ul) {
|
||||
quotient = integer / 100ul;
|
||||
remain = integer % 100ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[4], format, list);
|
||||
if(remain > 0 && 100ul / remain > 10) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
play_integer_number(remain, format, list);
|
||||
} else if (integer >= 10ul) {
|
||||
quotient = integer / 10ul;
|
||||
remain = integer % 10ul;
|
||||
play_integer_number(quotient, format, list);
|
||||
name_to_speech(sys_tone_measure[3], format, list);
|
||||
play_integer_number(remain, format, list);
|
||||
} else {
|
||||
quotient = integer % 10ul;
|
||||
if(quotient > 0) {
|
||||
name_to_speech(sys_tone_number[quotient], format, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 将金钱转换成语料文件添加进链表 */
|
||||
void money_to_speech(const char *value, char *format, struct core_list_head *list)
|
||||
{
|
||||
uint64_t integer = 0;
|
||||
uint32_t decimal = 0;
|
||||
uint32_t tmp_int = 0;
|
||||
char *dot = NULL, *end = NULL;
|
||||
|
||||
end = strstr(value, "}");
|
||||
if(end == NULL){
|
||||
return;
|
||||
}
|
||||
|
||||
dot = strstr(value, ".");
|
||||
if(dot != NULL){
|
||||
core_str2uint64((char *)value, dot - value, &integer);
|
||||
} else {
|
||||
core_str2uint64((char *)value, end - value, &integer);
|
||||
}
|
||||
|
||||
/*读取分数:分*/
|
||||
if(dot != NULL && dot[1] >= '0' && dot[1] <= '9') {
|
||||
decimal = (dot[1] - '0') * 10;
|
||||
if(dot[2] >= '0' && dot[2] <= '9') {
|
||||
decimal += (dot[2] - '0');
|
||||
}
|
||||
}
|
||||
|
||||
//元
|
||||
if(integer > 0) {
|
||||
play_integer_number(integer, format, list);
|
||||
name_to_speech(sys_tone_measure[2], format, list);
|
||||
}
|
||||
|
||||
if(decimal > 0) {
|
||||
//角
|
||||
tmp_int = decimal / 10;
|
||||
if(tmp_int > 0) {
|
||||
name_to_speech(sys_tone_number[tmp_int], format, list);
|
||||
name_to_speech(sys_tone_measure[1], format, list);
|
||||
} else if(integer > 0) {
|
||||
name_to_speech(sys_tone_number[0], format, list);
|
||||
}
|
||||
//分
|
||||
tmp_int = decimal % 10;
|
||||
if(tmp_int > 0) {
|
||||
name_to_speech(sys_tone_number[tmp_int], format, list);
|
||||
name_to_speech(sys_tone_measure[0], format, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.h
vendored
Normal file
17
sdk/合宙/air780e/csdk/luatos-soc-2022/thirdparty/linksdk/components/link-speech/speech_trans.h
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef __SPEECH_TRANS_H__
|
||||
#define __SPEECH_TRANS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include "core_list.h"
|
||||
|
||||
typedef struct {
|
||||
char *filename;
|
||||
struct core_list_head linked_node;
|
||||
} play_node_t;
|
||||
|
||||
/* 语料名字转换成文件添加进链表 */
|
||||
void name_to_speech(const char *value, char *format, struct core_list_head *list);
|
||||
/* 将金钱转换成语料文件添加进链表 */
|
||||
void money_to_speech(const char *value, char *format, struct core_list_head *list);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user