用Hi3861联网科大讯飞实现TTS功能

系统 OpenHarmony
因为业务需要,需要实现TTS功能。现讲开发过程和实现方式整理成文档,供有需要的人参考和讨论。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

因为业务需要,需要实现TTS功能。现讲开发过程和实现方式整理成文档,供有需要的人参考和讨论。

1、科大讯飞讯飞开放平台可以联网实现TTS功能,注册之后每天可以免费500次访问。

2、访问科大讯飞平台

目前访问需要Websocket API,​​帮助文档链接​​,具体的使用流程可以参看文档说明。

3、在Openharmony下移植websocket

访问websocket使用的是nopoll开源方案。将nopoll工程复制到third_party\nopoll下,在该文件下,添加BUILD.gn文件。

import("//build/lite/config/component/lite_component.gni")
import("//build/lite/ndk/ndk.gni")

config("nopoll_config") {
include_dirs = [
"nopoll",
"//device/hisilicon/hispark_pegasus/sdk_liteos/third_party/lwip_sack/include",
"//kernel/liteos_m/components/cmsis/2.0",
"//third_party/lwip/src/include",
"//third_party/tinycrypt/include",
]
}
cflags = [ "-Wno-unused-variable" ]
cflags += [ "-Wno-unused-but-set-variable" ]
cflags += [ "-Wno-unused-parameter" ]
cflags += [ "-Wno-sign-compare" ]
cflags += [ "-Wno-unused-function" ]
cflags += [ "-Wno-return-type" ]
nopoll_sources = [
"nopoll/nopoll.c",
"nopoll/nopoll_decl.c",
"nopoll/nopoll_win32.c",
"nopoll/nopoll_ctx.c",
"nopoll/nopoll_conn.c",
"nopoll/nopoll_log.c",
"nopoll/nopoll_listener.c",
"nopoll/nopoll_loop.c",
"nopoll/nopoll_io.c",
"nopoll/nopoll_msg.c",
"nopoll/nopoll_conn_opts.c",
"nopoll/nopoll_rtthread.c",
]
lite_library("nopoll_static") {
target_type = "static_library"
sources = nopoll_sources
public_configs = [ ":nopoll_config" ]
}
lite_library("nopoll_shared") {
target_type = "shared_library"
sources = nopoll_sources
public_configs = [ ":nopoll_config" ]
}
ndk_lib("nopoll_ndk") {
if (board_name != "hi3861v100") {
lib_extension = ".so"
deps = [
":nopoll_shared"
]
} else {
deps = [
":nopoll_static"
]
}
head_files = [
"//third_party/nopoll"
]
}

然后在工程的gn文件下,

4、实现websocket功能(关键代码)

nopoll还是很吃内存的,需要动态开辟很大的空间。因为考虑到空间,所以,转换的tts格式是mp3格式。

(1)websocket规则的日期获取

char *week[] = {"Mon, ", "Tues, ", "Wed, ", "Thur, ","Fri, ", "Sat, ","Sun, "};
char *month[] = {"", " Jan ", " Feb ", " Mar ", " Apr "," May ", " June "," July ", " Aug ", " Sept ", " Oct "," Nov ", " Dec "};
static void get_date(char *date)
{
int tv_sec = hi_get_real_time();
DEBUG_printf("hi_get_real_time=%d\r\n",tv_sec);
//timeutils_struct_time_t tm;
//timeutils_seconds_since_2000_to_struct_time(tv_sec, &tm);
time_t t = tv_sec;
struct tm *tm = localtime(&t);
// date: Tue, 15 Oct 2019 07:00:50 GMT
sprintf(date, "%s%02d%s%d%s%02d%s%02d%s%02d%s", week[tm->tm_wday], tm->tm_mday, month[tm->tm_mon], tm->tm_year+1900, " ",tm->tm_hour,":", tm->tm_min, ":", tm->tm_sec, " GMT");
}

因为需要校验时间,所以,设备需要联网,然后从网络拉取时间,进行时间更新。

(2)上传的json打包

void ws_xfyun_tts_request_json(char *buff)
{
char *string = NULL;
cJSON *root = cJSON_CreateObject();
//common
cJSON *cj_common = cJSON_CreateObject();
cJSON_AddItemToObject(root, "common", cj_common);
cJSON_AddItemToObject(cj_common, "app_id", cJSON_CreateString("0ea5cd21"));
//business
cJSON *cj_business = cJSON_CreateObject();
cJSON_AddItemToObject(root, "business", cj_business);
cJSON_AddItemToObject(cj_business, "aue", cJSON_CreateString("lame"));
cJSON_AddItemToObject(cj_business, "sfl", cJSON_CreateNumber(1));
cJSON_AddItemToObject(cj_business, "vcn",cJSON_CreateString("xiaoyan"));
cJSON_AddItemToObject(cj_business, "tte",cJSON_CreateString("UTF8"));
cJSON_AddItemToObject(cj_business, "pitch",cJSON_CreateNumber(50));
cJSON_AddItemToObject(cj_business, "speed",cJSON_CreateNumber(50));
//data
cJSON *cj_data = cJSON_CreateObject();
cJSON_AddItemToObject(root, "data", cj_data);
cJSON_AddItemToObject(cj_data, "status", cJSON_CreateNumber(2));
char base64_text[64];
int base64_len = sizeof(base64_text);
tiny_base64_encode(base64_text,&base64_len,tts_text,strlen(tts_text));
cJSON_AddItemToObject(cj_data, "text", cJSON_CreateString(base64_text));//北京 5YyX5Lqs
string = cJSON_PrintUnformatted(root);
strcpy(buff, string);
cJSON_Delete(root);
free(string);
}

(3)MP3解码

使用了helix库。

void mp3_decode_array(char *data,int len)
{
HMP3Decoder Decoder;
MP3FrameInfo mp3FrameInfo;
int bytesleft = len;
int decode_step = 0;;
unsigned short int output[1024*2];
Decoder = MP3InitDecoder();

int offset = MP3FindSyncWord(data,bytesleft); //搜索缓存中第一个有效数据帧
DEBUG_printf("offset = %d\r\n",offset);
if (offset < 0)
{
DEBUG_printf("MP3FindSyncWord not find.\r\n");
bytesleft = 0; // All data not avalible, clear the buffer.
return;
}
else if (offset > 0)
{
//去除头部无效数据
bytesleft -= offset;
decode_step += offset;
}
//以下解码n帧,readPtr会递增,bytesleft递减
unsigned char *readPtr;
readPtr = data+decode_step;
while (bytesleft > 0)
{
int ret = MP3Decode(Decoder, &readPtr, &bytesleft, (short *)output, 0);
if (ret == ERR_MP3_NONE) //正常解码
{
DEBUG_printf("decode ok:bytesleft=%d\r\n",bytesleft);
MP3GetLastFrameInfo(Decoder, &(mp3FrameInfo));
hi_i2s_write((unsigned char *)output, mp3FrameInfo.outputSamps * 2, 1000);
}
else//解码异常
{
DEBUG_printf("decode err: %d %d\r\n", ret,bytesleft);
}
}
DEBUG_printf("decode end.\r\n");
}

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2020-10-12 09:36:04

鸿蒙

2021-09-30 10:11:05

鸿蒙HarmonyOS应用

2022-03-07 15:05:58

HTTPHi3861数据解析

2020-10-16 09:50:37

Hi3861WiFi热点

2012-08-16 09:44:03

中国移动投资

2022-03-15 15:00:59

Hi3861Pin接口鸿蒙

2023-05-26 16:07:14

Hi3861Wifi模块

2022-05-30 15:21:27

Hi3861TCP通信

2020-11-02 12:07:11

鸿蒙 GPIO

2015-11-20 09:58:46

浪潮科大讯飞

2020-10-27 16:52:10

科大讯飞

2022-05-09 14:22:40

Hello WorlMNIST鸿蒙

2019-11-22 15:50:56

数字安全

2013-09-25 14:29:06

科大讯飞消费市场

2024-11-13 10:16:37

2020-10-28 10:03:43

Hi3861 GPIO点灯按键

2021-09-09 10:06:09

鸿蒙HarmonyOS应用

2020-10-14 09:41:02

Hi3861GPIO点灯

2016-08-15 17:21:02

联想

2015-10-23 13:41:20

android源码科大讯飞语音识别
点赞
收藏

51CTO技术栈公众号