UE4 Windows下对接百度语音识别

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 
#include 
#include 
#include 
#include 
#include 
#include 

const int __BCE_VERSION__ = 1;
const int __BCE_EXPIRE__ = 1800;

namespace aip {
    
    template
    std::basic_istream& getall(std::basic_istream& input,
                                              std::basic_string& 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 
#include 
#include 
#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 *)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 const & params, std::string * content) const
        {
            content->clear();
            std::map::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 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 const & headers, curl_slist ** slist) const
        {
            std::ostringstream ostr;
            std::map::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 const * params,
                std::map 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 const * params,
                 const std::string & body,
                 std::map 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 const * params,
                 std::map const & data,
                 std::map 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 const * params,
                 Json::Value const & data,
                 std::map const * headers,
                 std::string * response) const
        {
            std::string body;
            Json::StreamWriterBuilder swb;
            std::unique_ptr writer(swb.newStreamWriter());
            std::ostringstream os;
            writer->write(data, &os);
            body = os.str();
            std::map temp_headers;
            if (headers) {
                std::map 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 const * params,
                 std::map 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 
#include 
#include "http.h"
#include "json/json.h"
#include 
#include 
#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 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 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 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 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 & 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 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 const & options)
		{
			Json::Value data;

			std::map::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 options)
		{
			Json::Value data;
			std::map::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 const & options, std::string & file_content)
		{
			std::map data;
			std::map::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 
#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 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 
#include 
#include "Runtime/Core/Public/Async/AsyncWork.h"
#include "PrimeNumberWorker.h"

//#include 
//#include 



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 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 

/**
 *
 */
class  FPrimeNumberWorker : public FRunnable
{
	static  FPrimeNumberWorker* Runnable;
	FRunnableThread* Thread;
	TArray* 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& 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& 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& 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 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& 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.到目前为止开线程识别语音完成了,下面看效果

UE4 Windows下对接百度语音识别_第1张图片

UE4 Windows下对接百度语音识别_第2张图片

 

你可能感兴趣的:(UE4)