更新硬件SDK

This commit is contained in:
kerwincui
2023-03-04 03:44:56 +08:00
parent dcdf6e1b7c
commit e39d3d2f03
1900 changed files with 663153 additions and 0 deletions

View 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

View 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(&params, 0, sizeof(http_download_params_t));
params.https_enable = 1;
return core_http_download_request((char *)remote_url, &params, 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;
}

View 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 *) 1255, 默认为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__ */

View 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;
}

View 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_ */

View 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);
}
}
}

View 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