2

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

 2 years ago
source link: https://os.51cto.com/article/703208.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
用Hi3861联网科大讯飞实现TTS功能-51CTO.COM
用Hi3861联网科大讯飞实现TTS功能
作者:再见南丫岛 2022-03-04 15:51:43
因为业务需要,需要实现TTS功能。现讲开发过程和实现方式整理成文档,供有需要的人参考和讨论。

0684a6c1924ee1697cb5716a7dca6fbfcd97d1.png

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

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

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

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

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

0198461605dbcc51d7f4188d273accea39a5f4.png

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文件下,

c60aabc27436d9d7ca60813e85f56159729585.png

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​

172deba85aab72783f1840e0241edd0d4322e0.jpg


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK