|
|
@ -1,12 +1,30 @@ |
|
|
|
#include "asr_service.hpp"
|
|
|
|
|
|
|
|
#include "iflytopcpp/core/components/audio/wavheader.hpp"
|
|
|
|
#include "zlinuxcomponents/aiui_ws/aiui.h"
|
|
|
|
using namespace iflytop; |
|
|
|
using namespace core; |
|
|
|
using namespace std; |
|
|
|
|
|
|
|
static AiuiService *thisClass = nullptr; |
|
|
|
static string getTTSFileName() { |
|
|
|
static int i = 0; |
|
|
|
i++; |
|
|
|
if (i > 10) i = 0; |
|
|
|
return fmt::format("/tmp/aiui_service_tts{}.wav", i); |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* aiui的识别结果返回大致如下,先返回一个nlp识别结果的包,然后再返回多个包含tts音频数据的json包 |
|
|
|
* nlp->tts0->tts1->...->ttsn |
|
|
|
* 1. 通过json["data"]["sub"]来判断是什么包,sub的值有:nlp,tts |
|
|
|
* 2. 通过json["data"]["is_last"]判断是否是当前种类的最后一包. |
|
|
|
* 3. 通过json["data"]["is_finish"]判断是否是本次传输的最后一包 |
|
|
|
* |
|
|
|
*/ |
|
|
|
extern "C" { |
|
|
|
extern size_t aiui_base64_decode(char *source, unsigned char *target, size_t targetlen); |
|
|
|
} |
|
|
|
void aiui_message_cb(const char *data, int len) { |
|
|
|
if (thisClass) { |
|
|
|
thisClass->call_aiui_message_cb(data, len); |
|
|
@ -28,11 +46,78 @@ void AiuiService::aiuiDestroy() { |
|
|
|
aiui_destroy(); |
|
|
|
thisClass = nullptr; |
|
|
|
} |
|
|
|
void AiuiService::parseTTSContent(json &rxjson) { |
|
|
|
if (!oneAsrResultTransmition) { |
|
|
|
logger->error("oneAsrResultTransmition is null"); |
|
|
|
return; |
|
|
|
} |
|
|
|
/**
|
|
|
|
* @brief 解码base64数据,并保存起来 |
|
|
|
*/ |
|
|
|
string base64Data = rxjson["data"]["content"].get<string>(); |
|
|
|
size_t size = base64Data.size() * 3 / 4 + 50; |
|
|
|
shared_ptr<Binary> binary = make_shared<Binary>(size); |
|
|
|
size_t realsize = aiui_base64_decode((char *)base64Data.c_str(), binary->data(), size); |
|
|
|
binary->resize(realsize); |
|
|
|
oneAsrResultTransmition->ttsRawData.push_back(binary); |
|
|
|
} |
|
|
|
|
|
|
|
void AiuiService::endOneAsrResultTransmition() { |
|
|
|
/**
|
|
|
|
* @brief 如果是最后一包,则将接收到的tts保存成文件,然后同nlp结果打包在一起,然后上报。 |
|
|
|
*/ |
|
|
|
string ttsFileName = getTTSFileName(); |
|
|
|
FILE *fp = fopen(ttsFileName.c_str(), "wb"); |
|
|
|
size_t ttsframetotalsize = 0; |
|
|
|
for (auto &binary : oneAsrResultTransmition->ttsRawData) { |
|
|
|
ttsframetotalsize += binary->size(); |
|
|
|
} |
|
|
|
WAVHeader wavHeader(16000, 16, 1, ttsframetotalsize / 2); |
|
|
|
if (fp) { |
|
|
|
fwrite(wavHeader.data(), 1, wavHeader.size(), fp); |
|
|
|
for (auto &binary : oneAsrResultTransmition->ttsRawData) { |
|
|
|
fwrite(binary->data(), 1, binary->size(), fp); |
|
|
|
ttsframetotalsize += binary->size(); |
|
|
|
} |
|
|
|
fclose(fp); |
|
|
|
} |
|
|
|
oneAsrResultTransmition->asrResult["data"]["intent"]["answer"]["ttsurl"] = ttsFileName; |
|
|
|
/**
|
|
|
|
* @brief 上报识别结果 |
|
|
|
*/ |
|
|
|
onAsrResult(oneAsrResultTransmition->asrResult); |
|
|
|
oneAsrResultTransmition.reset(); |
|
|
|
} |
|
|
|
|
|
|
|
void AiuiService::call_aiui_message_cb(const char *data, int len) { |
|
|
|
try { |
|
|
|
json j = json::parse(data); |
|
|
|
onAsrResult(j); |
|
|
|
if (!oneAsrResultTransmition) { |
|
|
|
oneAsrResultTransmition = make_unique<OneAsrResultTransmition>(); |
|
|
|
logger->info("start rx aiui data"); |
|
|
|
} |
|
|
|
json rxjson = json::parse(data); |
|
|
|
if (rxjson["action"].get<string>() != "result") { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief 处理接收到的数据 |
|
|
|
*/ |
|
|
|
if (rxjson["data"]["sub"].get<string>() == "nlp") { |
|
|
|
// 解析nlpcontent
|
|
|
|
oneAsrResultTransmition->asrResult = rxjson; |
|
|
|
} else if (rxjson["data"]["sub"].get<string>() == "tts") { |
|
|
|
// 解析ttscontent
|
|
|
|
parseTTSContent(rxjson); |
|
|
|
} |
|
|
|
/**
|
|
|
|
* @brief 结束本次接收 |
|
|
|
*/ |
|
|
|
if (rxjson["data"]["is_finish"].get<bool>()) { |
|
|
|
logger->info("end rx aiui data"); |
|
|
|
// will call onAsrResult in this function
|
|
|
|
endOneAsrResultTransmition(); |
|
|
|
} |
|
|
|
} catch (const std::exception &e) { |
|
|
|
logger->error("AiuiService::call_aiui_message_cb error: {}", e.what()); |
|
|
|
} |
|
|
|