1.首先前期准备工作:
a.编译openssl:进入openssl目录(这里以64位系统为例)
x64: VC-WIN64A ms\do_win64a.bat x32: VC-WIN32 ms\do_ms.bat
静态库
perl Configure VC-WIN64A no-asm --prefix="C:\Users\Administrator\Desktop\BaiduVoice\openssl\openssl_lib\jingtai"
ms\do_win64a.bat
nmake -f ms\nt.mak
nmake -f ms\nt.mak test
nmake -f ms\nt.mak install
nmake -f ms\nt.mak clean
动态库
perl Configure VC-WIN64A --prefix="C:\Users\Administrator\Desktop\BaiduVoice\openssl\openssl_lib\dongtai"
ms\do_win64a.bat
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak test
nmake -f ms\ntdll.mak install
nmake -f ms\ntdll.mak clean
参考:https://blog.csdn.net/y601500359/article/details/89518497
b.编译curl/libcurl:进入winbuild目录
静态:nmake /f Makefile.vc mode=static VC=17 WITH_DEVEL=C:\Users\Administrator\Desktop\BaiduVoice\openssl\openssl_lib\jingtai WITH_SSL=static ENABLE_SSPI=no ENABLE_IPV6=no
动态:nmake /f Makefile.vc mode=dll VC=17 WITH_DEVEL=C:\Users\Administrator\Desktop\BaiduVoice\openssl\openssl_lib\dongtai WITH_SSL=dll ENABLE_SSPI=no ENABLE_IPV6=no
测试:curl.exe http://www.meixxx.com/
curl.exe https://mail.qq.com -k
参考:https://www.cnblogs.com/openiris/p/3812443.html
c.编译json:(百度说要1.6以上的版本,下载地址https://github.com/open-source-parsers/jsoncpp)
参考:https://www.cnblogs.com/openiris/p/3812443.html
2.把百度的.h文件照着写到UE4中,这里只写了识别本地语音
utils.h
#pragma once
#include <string>
#include <fstream>
#include <ctype.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <algorithm>
#include <openssl/md5.h>
const int __BCE_VERSION__ = 1;
const int __BCE_EXPIRE__ = 1800;
namespace aip {
template<class CharT, class Traits, class Allocator>
std::basic_istream<CharT, Traits>& getall(std::basic_istream<CharT, Traits>& input,
std::basic_string<CharT, Traits, Allocator>& str) {
std::ostringstream oss;
oss << input.rdbuf();
str.assign(oss.str());
return input;
}
inline int get_file_content(const char *filename, std::string* out) {
std::ifstream in(filename, std::ios::in | std::ios::binary);
if (in) {
getall(in, *out);
return 0;
} else {
return -1;
}
}
}
http.h
/**
* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @author baidu aip
*/
#pragma once
#include "curl/curl.h"
#include <sstream>
#include <string>
#include <map>
#include "json/json.h"
inline size_t onWriteData(void * buffer, size_t size, size_t nmemb, void * userp)
{
std::string * str = dynamic_cast<std::string *>((std::string *)userp);
str->append((char *)buffer, size * nmemb);
return nmemb;
}
class HttpClient
{
private:
bool debug = false;
int connect_timeout = 10000;
int socket_timeout = 10000;
void makeUrlencodedForm(std::map<std::string, std::string> const & params, std::string * content) const
{
content->clear();
std::map<std::string, std::string>::const_iterator it;
for(it=params.begin(); it!=params.end(); it++)
{
char * key = curl_escape(it->first.c_str(), (int) it->first.size());
char * value = curl_escape(it->second.c_str(),(int) it->second.size());
*content += key;
*content += '=';
*content += value;
*content += '&';
curl_free(key);
curl_free(value);
}
}
void appendUrlParams(std::map<std::string, std::string> const & params, std::string* url) const
{
if(params.empty()) {
return;
}
std::string content;
this->makeUrlencodedForm(params, &content);
bool url_has_param = false;
for (const auto& ch : *url) {
if (ch == '?') {
url_has_param = true;
break;
}
}
if (url_has_param) {
url->append("&");
} else {
url->append("?");
}
url->append(content);
}
void appendHeaders(std::map<std::string, std::string> const & headers, curl_slist ** slist) const
{
std::ostringstream ostr;
std::map<std::string, std::string>::const_iterator it;
for(it=headers.begin(); it!=headers.end(); it++)
{
ostr << it->first << ":" << it->second;
*slist = curl_slist_append(*slist, ostr.str().c_str());
ostr.str("");
}
}
public:
HttpClient() = default;
HttpClient(const HttpClient &) = delete;
HttpClient & operator=(const HttpClient &) = delete;
void setConnectTimeout(int connect_timeout)
{
this->connect_timeout = connect_timeout;
}
void setSocketTimeout(int socket_timeout)
{
this->socket_timeout = socket_timeout;
}
void setDebug(bool debug)
{
this->debug = debug;
}
int get(
std::string url,
std::map<std::string, std::string> const * params,
std::map<std::string, std::string> const * headers,
std::string * response) const
{
CURL * curl = curl_easy_init();
struct curl_slist * slist = NULL;
if (headers) {
this->appendHeaders(*headers, &slist);
}
if (params) {
this->appendUrlParams(*params, &url);
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) response);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, true);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, this->connect_timeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, this->socket_timeout);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_VERBOSE, this->debug);
int status_code = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_slist_free_all(slist);
return status_code;
}
int post(
std::string url,
std::map<std::string, std::string> const * params,
const std::string & body,
std::map<std::string, std::string> const * headers,
std::string * response) const
{
struct curl_slist * slist = NULL;
CURL * curl = curl_easy_init();
if (headers) {
this->appendHeaders(*headers, &slist);
}
if (params) {
this->appendUrlParams(*params, &url);
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.size());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onWriteData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) response);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, true);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, this->connect_timeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, this->socket_timeout);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_VERBOSE, this->debug);
int status_code = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_slist_free_all(slist);
return status_code;
}
int post(
std::string url,
std::map<std::string, std::string> const * params,
std::map<std::string, std::string> const & data,
std::map<std::string, std::string> const * headers,
std::string * response) const
{
std::string body;
this->makeUrlencodedForm(data, &body);
return this->post(std::move(url), params, body, headers, response);
}
int post(
std::string url,
std::map<std::string, std::string> const * params,
Json::Value const & data,
std::map<std::string, std::string> const * headers,
std::string * response) const
{
std::string body;
Json::StreamWriterBuilder swb;
std::unique_ptr<Json::StreamWriter> writer(swb.newStreamWriter());
std::ostringstream os;
writer->write(data, &os);
body = os.str();
std::map<std::string, std::string> temp_headers;
if (headers) {
std::map<std::string, std::string> temp_headers(*headers);
}
temp_headers["Content-Type"] = "application/json";
return this->post(url.c_str(), params, body, &temp_headers, response);
}
int post(
std::string url,
std::map<std::string, std::string> const * params,
std::map<std::string, std::string> const * headers,
std::string * response) const
{
const static std::string EMPTY_STRING;
return this->post(std::move(url), params, EMPTY_STRING, headers, response);
}
};
base.h
/**
* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @author baidu aip
*/
#pragma once
#include <memory>
#include <cstring>
#include "http.h"
#include "json/json.h"
#include <iostream>
#include <string>
#include "curl/curl.h"
#include "utils.h"
static const char* AIP_SDK_VERSION = "0.7.4";
static const char* CURL_ERROR_CODE = "curl_error_code";
static const std::string ACCESS_TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token";
static const std::map<std::string, std::string> null;
enum class VECTOR_JOIN_TYPE {BASE64, URL};
class AipBase
{
private:
std::string _app_id;
int _expired_time;
bool _is_bce;
std::string _scope;
protected:
std::string getAccessToken()
{
time_t now = time(NULL);
if (!access_token.empty() && now < this->_expired_time - 60 * 60 * 24)
{
return this->access_token;
}
std::string response;
std::map<std::string, std::string> params;
params["grant_type"] = "client_credentials";
params["client_id"] = this->ak;
params["client_secret"] = this->sk;
int status_code = this->client.get(
ACCESS_TOKEN_URL,
¶ms,
nullptr,
&response
);
Json::Value obj;
if (status_code != CURLcode::CURLE_OK) {
obj[CURL_ERROR_CODE] = status_code;
return obj.toStyledString();
}
std::string error;
std::unique_ptr<Json::CharReader> reader(crbuilder.newCharReader());
reader->parse(response.data(), response.data() + response.size(), &obj, &error);
this->access_token = obj["access_token"].asString();
this->_expired_time = obj["expires_in"].asInt() + (int) now;
this->_scope = obj["scope"].asString();
return this->access_token;
}
public:
std::string ak;
std::string sk;
HttpClient client;
Json::CharReaderBuilder crbuilder;
std::string access_token;
AipBase(const std::string & app_id, const std::string & ak, const std::string & sk):
_app_id(app_id),
_is_bce(false),
ak(ak),
sk(sk)
{
if (_app_id == "")
{
}
}
void set_is_bce() {
_is_bce = true;
}
void setConnectionTimeoutInMillis(int connect_timeout)
{
this->client.setConnectTimeout(connect_timeout);
}
void setSocketTimeoutInMillis(int socket_timeout)
{
this->client.setSocketTimeout(socket_timeout);
}
void setDebug(bool debug)
{
this->client.setDebug(debug);
}
std::string getAk() {
return ak;
}
const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
inline bool is_base64(const char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(const char * bytes_to_encode, unsigned int in_len)
{
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--)
{
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
{
ret += base64_chars[char_array_4[i]];
}
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
{
char_array_3[j] = '\0';
}
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
{
ret += base64_chars[char_array_4[j]];
}
while ((i++ < 3))
{
ret += '=';
}
}
return ret;
}
std::string base64_decode(std::string const & encoded_string)
{
int in_len = (int)encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++)
char_array_4[j] = 0;
for (j = 0; j < 4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
};
speech.h
#pragma once
#include "base.h"
#include "json/json.h"
class Speech : public AipBase
{
public:
std::string _asr = "https://vop.baidu.com/server_api";
std::string _tts = "http://tsn.baidu.com/text2audio";
Speech(const std::string app_id, const std::string & ak, const std::string & sk) : AipBase(app_id, ak, sk)
{
}
Json::Value request_asr(
std::string const & url,
Json::Value & data)
{
std::string response;
Json::Value obj;
int status_code = this->client.post(url, nullptr, data, nullptr, &response);
if (status_code != CURLcode::CURLE_OK) {
obj[CURL_ERROR_CODE] = status_code;
return obj;
}
std::string error;
std::unique_ptr<Json::CharReader> reader(crbuilder.newCharReader());
reader->parse(response.data(), response.data() + response.size(), &obj, &error);
return obj;
}
Json::Value request_tts(
const std::string url,
std::map<std::string, std::string> & data,
std::string & file_content)
{
std::string response;
Json::Value obj;
Json::Value file_json;
int status_code = this->client.post(url, nullptr, data, nullptr, &response);
if (status_code != CURLcode::CURLE_OK) {
obj[CURL_ERROR_CODE] = status_code;
return obj;
}
std::string error;
std::unique_ptr<Json::CharReader> reader(crbuilder.newCharReader());
reader->parse(response.data(), response.data() + response.size(), &obj, &error);
if (error.empty()) {
// 接口返回错误信息
obj[CURL_ERROR_CODE] = 0;
}
else {
// 接口返回语音文件
file_content = response;
}
return obj;
}
Json::Value recognize(const std::string voice_binary, const std::string & format, const int & rate, std::map<std::string, std::string> const & options)
{
Json::Value data;
std::map<std::string, std::string>::const_iterator it;
for (it = options.begin(); it != options.end(); it++)
{
data[it->first] = it->second;
}
std::string token = this->getAccessToken();
data["speech"] = base64_encode(voice_binary.c_str(), (int)voice_binary.size());
data["format"] = format;
data["rate"] = std::to_string(rate);
data["channel"] = "1";
data["token"] = token;
data["cuid"] = this->getAk();
data["len"] = (int)voice_binary.size();
Json::Value result = this->request_asr(_asr, data);
return result;
}
Json::Value recognize_url(const std::string & url,
const std::string & callback, const std::string & format,
const int & rate,
std::map<std::string, std::string> options)
{
Json::Value data;
std::map<std::string, std::string>::iterator it;
for (it = options.begin(); it != options.end(); it++)
{
data[it->first] = it->second;
}
std::string token = this->getAccessToken();
data["url"] = url;
data["callback"] = callback;
data["format"] = format;
data["rate"] = std::to_string(rate);
data["channel"] = 1;
data["token"] = token;
data["cuid"] = this->getAk();
Json::Value result = this->request_asr(_asr, data);
return result;
}
Json::Value text2audio(const std::string & text, std::map<std::string, std::string> const & options, std::string & file_content)
{
std::map<std::string, std::string> data;
std::map<std::string, std::string>::const_iterator it;
for (it = options.begin(); it != options.end(); it++)
{
data[it->first] = it->second;
}
std::string token = this->getAccessToken();
data["tex"] = text;
data["lan"] = "zh";
data["ctp"] = "1";
data["tok"] = token;
data["cuid"] = this->getAk();
Json::Value result = this->request_tts(_tts, data, file_content);
return result;
}
};
BaiduActor.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/Actor.h"
#include "speech.h"
#include <sstream>
#include "BaiduActor.generated.h"
UCLASS()
class ABaiduActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ABaiduActor();
~ABaiduActor();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
// The device ID opened by the Video Stream
//Speech* client;
void ASR(Speech* client);
TArray<FString> PrimeNumbers;
UFUNCTION(BlueprintCallable, Category = "My|ThreadActor")
void MyAsyncSuspend();
UFUNCTION(BlueprintCallable, Category = "My|ThreadActor")
void MyAsyncResume();
UFUNCTION(BlueprintCallable, Category = "My|ThreadActor")
void MyAsyncThread();
void BeginDestroy() override;
//UFUNCTION(BlueprintCallable, Category = BaiduSpeechRecognizer)
// void InitBaiduSpeechRecognizer(FString appid, FString ApiKey, FString SecretKey);
UFUNCTION(BlueprintCallable, Category = BaiduSpeechRecognizer)
void GetBaiduSpeechRecognizer();//FString soundUrl, FString geshi
//UPROPERTY(BlueprintReadOnly, Category = "Snowing")
FString content;
};
BaiduVoice.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "BaiduActor.h"
#include <Engine/Engine.h>
#include <string>
#include "Runtime/Core/Public/Async/AsyncWork.h"
#include "PrimeNumberWorker.h"
//#include <fstream>
//#include <iostream>
ABaiduActor::ABaiduActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
ABaiduActor::~ABaiduActor()
{
FPrimeNumberWorker::Shutdown();
}
// Called when the game starts or when spawned
void ABaiduActor::BeginPlay()
{
Super::BeginPlay();
//client->AA();
}
// Called every frame
void ABaiduActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ABaiduActor::ASR(Speech* client)
{
std::map<std::string, std::string> options;
options["lan"] = "ZH";//dev_pid
std::string file_content;
aip::get_file_content("D:/UE4project/AAB/16k_test.pcm", &file_content); //D:/UE4project/A4222/16k_test.pcm TCHAR_TO_UTF8(*soundUrl)
Json::Value result = client->recognize(file_content, "pcm", 16000, options);
//std::cout << "语音识别本地文件结果:" << std::endl << result.toStyledString();
//FString aa = UTF8_TO_TCHAR(result.toStyledString().c_str());
std::string aa = result.toStyledString();
content = UTF8_TO_TCHAR(aa.c_str());
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, FString::Printf(TEXT("语音识别本地文件结果:%s"), *content));
//.c_str()
}
void ABaiduActor::MyAsyncSuspend()
{
FPrimeNumberWorker::Get()->Suspend();
}
void ABaiduActor::MyAsyncResume()
{
FPrimeNumberWorker::Get()->Resume();
}
void ABaiduActor::MyAsyncThread()
{
Speech* client = new Speech("16388124", "4KKocT8mpeOBviU60vKKUQNL", "1qAO159LFRuFiLRylK8COS9N7GSRPkBU");
FTimerHandle mTimer;
PrimeNumbers.Empty();
FPrimeNumberWorker::JoyInit(PrimeNumbers, this, client);
GetWorldTimerManager().SetTimer(mTimer, [&]()->void {
FPrimeNumberWorker* pnw = FPrimeNumberWorker::Get();
if (!pnw)
return;
FCriticalSection* cs = pnw->GetCriticalSection(); //获取FPrimeNumberWorker到中的互斥锁QueueCritical
//if (cs )
//{
//FScopeLock QueueLock(cs);//锁住,等作用域过后QueueLock自动析构解锁 卡住
UE_LOG(LogTemp, Warning, TEXT("--- AMyActor::MyAsyncThread, PrimeNumbers.Num=%d"), PrimeNumbers.Num());
//}
/* if (PrimeNumbers.Num() != 0 && PrimeNumbers.Last())
{
UE_LOG(LogTemp, Warning, TEXT("%s"), *PrimeNumbers.Last());
}*/
if (pnw->IsThreadFinished() && pnw)
FPrimeNumberWorker::Shutdown();
}, 1.0f, true);
}
void ABaiduActor::BeginDestroy()
{
Super::BeginDestroy();
FPrimeNumberWorker::Shutdown();
UE_LOG(LogTemp, Warning, TEXT("Game exit!"));
}
void ABaiduActor::GetBaiduSpeechRecognizer()
{
Speech* client = new Speech("16388124", "4KKocT8mpeOBviU60vKKUQNL", "1qAO159LFRuFiLRylK8COS9N7GSRPkBU");
}
PrimeNumberWorker.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Runnable.h"
#include "speech.h"
#include "CoreMinimal.h"
#include <GameFramework/Actor.h>
/**
*
*/
class FPrimeNumberWorker : public FRunnable
{
static FPrimeNumberWorker* Runnable;
FRunnableThread* Thread;
TArray<FString>* PrimeNumbers;
AActor* mmyActor;
FThreadSafeCounter StopTaskCounter; //用于多线程间的判断交互,volatile int32 Counter;
int32 FindNextPrimeNumber();
FCriticalSection QueueCritical; //互斥锁
FEvent* ThreadSuspendedEvent; //线程悬挂和唤醒事件
public:
bool IsFinished();
void Suspend();
void Resume();
//Constructor / Destructor
FPrimeNumberWorker(TArray<FString>& TheArray, AActor* myActor, Speech* client); //第三个变量为测试
virtual ~FPrimeNumberWorker();
// Begin FRunnable interface.
virtual bool Init();
virtual uint32 Run();
virtual void Stop();
// End FRunnable interface
/** Makes sure this thread has stopped properly */
void EnsureCompletion();
FCriticalSection* GetCriticalSection();
/*
Start the thread and the worker from static (easy access)!
This code ensures only 1 Prime Number thread will be able to run at a time.
This function returns a handle to the newly started instance.
*/
static FPrimeNumberWorker* JoyInit(TArray<FString>& TheArray, AActor* myActor, Speech* client);//第三个变量为测试
static FPrimeNumberWorker* Get();
static void Shutdown();
static bool IsThreadFinished();
public:
int32 mPrimesFoundCount;
Speech* mclient;
//~~~ Thread Core Functions ~~~
};
PrimeNumberWorker.cpp
#include "PrimeNumberWorker.h"
//***********************************************************
//Thread Worker Starts as NULL, prior to being instanced
// This line is essential! Compiler error without it
FPrimeNumberWorker* FPrimeNumberWorker::Runnable = nullptr;
//***********************************************************
FPrimeNumberWorker::FPrimeNumberWorker(TArray<FString>& TheArray, AActor* myActor, Speech* client)
: mmyActor(myActor)
, StopTaskCounter(0)
, mclient(client)//Test
{
ThreadSuspendedEvent = FPlatformProcess::GetSynchEventFromPool();
PrimeNumbers = &TheArray;
Thread = FRunnableThread::Create(this, TEXT("FPrimeNumberWorker"), 0, TPri_BelowNormal); //windows default = 8mb for thread, could specify more
}
FPrimeNumberWorker::~FPrimeNumberWorker()
{
delete Thread;
Thread = nullptr;
FPlatformProcess::ReturnSynchEventToPool(ThreadSuspendedEvent);
ThreadSuspendedEvent = nullptr;
}
bool FPrimeNumberWorker::Init()
{
//uint32 Allsize;
//uint8 element = 0;
//PrimeNumbers.Init(element, FMath::Min( Allsize, 4096u));
PrimeNumbers->Empty();
//PrimeNumbers->Add(2);
//PrimeNumbers->Add(3);
if (mmyActor)
{
UE_LOG(LogTemp, Warning, TEXT("**********************************"));
UE_LOG(LogTemp, Warning, TEXT("Prime Number Thread Started!"));
UE_LOG(LogTemp, Warning, TEXT("**********************************"));
}
return true;
}
uint32 FPrimeNumberWorker::Run()
{
//Initial wait before starting
FPlatformProcess::Sleep(0.03);
// While not told to stop this thread
// and not yet finished finding Prime Numbers
while (StopTaskCounter.GetValue() == 0 && !IsFinished())
{
//FScopeLock* QueueLock = new FScopeLock(&QueueCritical); //锁住
UE_LOG(LogTemp, Warning, TEXT("--- FPrimeNumberWorker::Run, lock"));
//***************************************
if (PrimeNumbers && mclient)
{
std::map<std::string, std::string> options;
options["lan"] = "ZH";//dev_pid
std::string file_content;
aip::get_file_content("D:/UE4project/AAB/16k_test.pcm", &file_content); //D:/UE4project/A4222/16k_test.pcm TCHAR_TO_UTF8(*soundUrl)
Json::Value result = mclient->recognize(file_content, "pcm", 16000, options);
//std::cout << "语音识别本地文件结果:" << std::endl << result.toStyledString();
//FString aa = UTF8_TO_TCHAR(result.toStyledString().c_str());
std::string aa = result.toStyledString();
FString content = UTF8_TO_TCHAR(aa.c_str());
PrimeNumbers->Push(content);
UE_LOG(LogTemp, Warning, TEXT("%s"), *PrimeNumbers->Last());
}
else
{
UE_LOG(LogTemp, Warning, TEXT("No PrimeNumbers client"));
}//不要 spawning / modifying / deleting UObjects / AActors 等等之类的事
//这里做多线程间共享信息的 modify,如:PrimeNumbers->Add
//***************************************
//PrimeNumbers->Add(FindNextPrimeNumber());
//PrimeNumbers->Add(UTF8_TO_TCHAR(result.toStyledString().c_str()));
//GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, FString::Printf(TEXT("语音识别本地文件结果:%s"), *content));
//***************************************
//Show Incremental Results in Main Game Thread!
// Please note you should not create, destroy, or modify UObjects here.
// Do those sort of things after all thread are completed.
// All calcs for making stuff can be done in the threads
// But the actual making/modifying of the UObjects should be done in main game thread.
//***************************************
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//prevent thread from using too many resources
//FPlatformProcess::Sleep(0.01);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//PrimeNumbers->Add(FindNextPrimeNumber());
//Suspend();
//prevent thread from using too many resources
//FPlatformProcess::Sleep(1.0f); //这里睡眠3秒是为了让GameThread中的AActor::MyAsyncThread中的日志打不出来
//delete QueueLock;//解锁
UE_LOG(LogTemp, Warning, TEXT("--- FPrimeNumberWorker::Run, unlock"));
FPlatformProcess::Sleep(2.0f); //这里睡眠2秒是为了让GameThread中获取到 互斥锁QueueCritical 并锁住
//UE_LOG(LogTemp, Warning, TEXT("%s"), *content);
//UE_LOG(LogTemp, Warning, TEXT("%s"), *PrimeNumbers->Last());
}
Stop();
//Run FPrimeNumberWorker::Shutdown() from the timer in Game Thread that is watching
//to see when FPrimeNumberWorker::IsThreadFinished()
return 0;
}
bool FPrimeNumberWorker::IsFinished()
{
return PrimeNumbers->Num() == 5;
}
void FPrimeNumberWorker::Suspend()
{
ThreadSuspendedEvent->Wait();
}
void FPrimeNumberWorker::Resume()
{
ThreadSuspendedEvent->Trigger();
}
void FPrimeNumberWorker::Stop()
{
StopTaskCounter.Increment();
}
FPrimeNumberWorker* FPrimeNumberWorker::JoyInit(TArray<FString>& TheArray, AActor* myActor, Speech* client)
{
//Create new instance of thread if it does not exist
// and the platform supports multi threading!
if (!Runnable && FPlatformProcess::SupportsMultithreading())
{
Runnable = new FPrimeNumberWorker(TheArray, myActor, client);
}
bool isSupport = FPlatformProcess::SupportsMultithreading();
FString msg = isSupport ? "SupportsMultithread" : "dont SupportsMultithreading";
UE_LOG(LogTemp, Warning, TEXT("--- FPrimeNumberWorker::JoyInit, msg:%s"), *msg);
return Runnable;
}
FPrimeNumberWorker* FPrimeNumberWorker::Get()
{
return Runnable;
}
void FPrimeNumberWorker::EnsureCompletion()
{
Stop();
Thread->WaitForCompletion();
}
FCriticalSection* FPrimeNumberWorker::GetCriticalSection()
{
return &QueueCritical;
}
void FPrimeNumberWorker::Shutdown()
{
if (Runnable)
{
Runnable->EnsureCompletion();
delete Runnable;
Runnable = nullptr;
}
}
bool FPrimeNumberWorker::IsThreadFinished()
{
if (Runnable) return Runnable->IsFinished();
return true;
}
int32 FPrimeNumberWorker::FindNextPrimeNumber()
{
int32 TestPrime = 123;
return TestPrime;
}
3.到目前为止开线程识别语音完成了,下面看效果