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

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

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

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

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

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

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

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

2、访问科大讯飞平台

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

3、在Openharmony下移植websocket

访问websocket使用的是nopoll开源方案。将nopoll工程复制到third_partynopoll下,在该文件下,添加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文件下,

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

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=%drn",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 = %drn",offset);
if (offset < 0)
{
DEBUG_printf("MP3FindSyncWord not find.rn");
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=%drn",bytesleft);
MP3GetLastFrameInfo(Decoder, &(mp3FrameInfo));
hi_i2s_write((unsigned char *)output, mp3FrameInfo.outputSamps * 2, 1000);
}
else//解码异常
{
DEBUG_printf("decode err: %d %drn", ret,bytesleft);
}
}
DEBUG_printf("decode end.rn");
}

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

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

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

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

文章版权声明

 1 原创文章作者:天道愁勤,如若转载,请注明出处: https://www.52hwl.com/94065.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2024年1月16日 下午10:02
下一篇 2024年1月16日 下午10:03