目录
一、总体介绍
用到的技术:科大讯飞的aiui和语音唤醒
科大讯飞的aiui:用来实现语音交互的功能
语音唤醒:用来触发aiui的功能
操作系统:ubuntu16.04(Linux)
二、唤醒
实现唤醒的功能可以看之前的文章:
http://t.csdnimg.cn/3mf18
三、将语音唤醒和aiui结合
(1)项目合并
我们以aiui的项目为基础,将语音唤醒的项目合并到aiui。
文件夹合并整理
(2)修改CMakeList.txt
注意:如果不了解CMakeList.txt,推荐看之前的文章
target_link_libraries(${PROJECT_NAME} libpthread.so -lasound -lstdc++ aikit pthread dl asound)
代码分析
这段代码是 CMake 中使用的 add_custom_command 命令,用于在构建目标(TARGET)后执行自定义命令。在这个代码中,这些自定义命令被添加到了项目(PROJECT_NAME)的构建过程中,并且被设置为在构建完成后执行(POST_BUILD)。
这样做的目的是将一些依赖的动态链接库文件或者其他必要的资源文件在构建完成后一同复制到可执行文件的输出目录,以便于程序在运行时能够正常访问这些文件。通常情况下,这些文件可能是程序运行所需的第三方库文件、配置文件或者其他资源文件。
总结:这段代码的作用就是在构建完成后将指定的文件复制到可执行文件的输出目录,以满足程序运行时对这些文件的依赖。
(3)demo代码修改
1.添加库
2.在demo中添加唤醒功能的代码
//将唤醒的代码添加在aiui的后面
#define SAMPLE_RATE_16K (16000)
#define DEFAULT_FORMAT \
{\
WAVE_FORMAT_PCM, \
1, \
16000, \
32000, \
2, \
16, \
sizeof(WAVEFORMATEX) \
}
#define E_SR_NOACTIVEDEVICE 1
#define E_SR_NOMEM 2
#define E_SR_INVAL 3
#define E_SR_RECORDFAIL 4
#define E_SR_ALREADY 5
int times = 1;
struct recorder* recorder;
void sleep_ms(int ms)
{
usleep(ms * 1000);
}
//唤醒结果在此回调
void OnOutput(AIKIT_HANDLE* handle, const AIKIT_OutputData* output) {
string temp = (char*)output->node->value;
printf("OnOutput abilityID :%s\n", handle->abilityID);
printf("OnOutput key:%s\n", output->node->key);
printf("OnOutput value:%s\n", (char*)output->node->value);
}
void OnEvent(AIKIT_HANDLE* handle, AIKIT_EVENT eventType, const AIKIT_OutputEvent* eventValue) {
printf("OnEvent:%d\n", eventType);
}
void OnError(AIKIT_HANDLE* handle, int32_t err, const char* desc) {
printf("OnError:%d\n", err);
}
void iat_cb(char* dataBuf, unsigned long len, void* user_para)
{
int errcode = 0;
AIKIT_HANDLE* handle = (AIKIT_HANDLE*)user_para;
if (len == 0 || dataBuf == NULL)
{
return;
}
AIKIT_DataBuilder* dataBuilder = AIKIT_DataBuilder::create();
AiAudio* wavData = AiAudio::get("wav")->data(dataBuf, len)->valid();
dataBuilder->payload(wavData);
int ret = AIKIT_Write(handle, AIKIT_Builder::build(dataBuilder));
if (ret != 0) {
printf("AIKIT_Write:%d\n", ret);
}
}
void ivwIns() {
AIKIT_ParamBuilder* paramBuilder = nullptr;
AIKIT_HANDLE* handle = nullptr;
int index[] = { 0 };
int ret = 0;
int err_code = 0;
int count = 0;
paramBuilder = AIKIT_ParamBuilder::create();
WAVEFORMATEX wavfmt = DEFAULT_FORMAT;
wavfmt.nSamplesPerSec = SAMPLE_RATE_16K;
wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec;
if (times == 1) {
AIKIT_CustomData customData;
customData.key = "key_word";
customData.index = 0;
customData.from = AIKIT_DATA_PTR_PATH;
customData.value = (void*)"./resource/keyword-nhxd.txt";
customData.len = strlen("./resource/keyword-nhxd.txt");
customData.next = nullptr;
customData.reserved = nullptr;
printf("AIKIT_LoadData start!\n");
ret = AIKIT_LoadData("e867a88f2", &customData);
printf("AIKIT_LoadData end!\n");
printf("AIKIT_LoadData:%d\n", ret);
if (ret != 0) {
goto exit;
}
times++;
}
ret = AIKIT_SpecifyDataSet("e867a88f2", "key_word", index, 1);
printf("AIKIT_SpecifyDataSet:%d\n", ret);
if (ret != 0) {
goto exit;
}
paramBuilder->param("wdec_param_nCmThreshold", "0 0:999", 8);
paramBuilder->param("gramLoad", true);
ret = AIKIT_Start("e867a88f2", AIKIT_Builder::build(paramBuilder), nullptr, &handle);
printf("AIKIT_Start:%d\n", ret);
if (ret != 0) {
goto exit;
}
err_code = create_recorder(&recorder, iat_cb, (void*)handle);
if (recorder == NULL || err_code != 0) {
printf("create recorder failed: %d\n", err_code);
err_code = -E_SR_RECORDFAIL;
goto exit;
}
err_code = open_recorder(recorder, get_default_input_dev(), &wavfmt);
if (err_code != 0) {
printf("recorder open failed: %d\n", err_code);
err_code = -E_SR_RECORDFAIL;
goto exit;
}
err_code = start_record(recorder);
if (err_code != 0) {
printf("start record failed: %d\n", err_code);
err_code = -E_SR_RECORDFAIL;
goto exit;
}
//监听
while (1)
{
sleep_ms(200);
printf("Listening...\n");
count++;
if (count % 20 == 0)
{
stop_record(recorder);
close_recorder(recorder);
destroy_recorder(recorder);
recorder = NULL;
//struct recorder *recorder;
err_code = create_recorder(&recorder, iat_cb, (void*)handle);
err_code = open_recorder(recorder, get_default_input_dev(), &wavfmt);
err_code = start_record(recorder);
}
}
ret = AIKIT_End(handle);
exit:
if (paramBuilder != nullptr)
{
delete paramBuilder;
paramBuilder = nullptr;
}
}
void TestIVW() {
AIKIT_Configurator::builder()
.app()
.appID("去科大讯飞找")
.apiKey("去科大讯飞找")
.apiSecret("去科大讯飞找")
.workDir("./")
.auth()
.authType(0)
.ability("e867a88f2")
.log()
.logLevel(LOG_LVL_INFO);
AIKIT_Callbacks cbs = { OnOutput,OnEvent,OnError };
AIKIT_RegisterAbilityCallback("e867a88f2", cbs);
AIKIT_SetILogOpen(false);
int ret = AIKIT_Init();
if (ret != 0) {
printf("AIKIT_Init failed:%d\n", ret);
goto exit;
}
ret = AIKIT_EngineInit("e867a88f2", nullptr);
if (ret != 0) {
printf("AIKIT_EngineInit failed:%d\n", ret);
goto exit;
}
ivwIns();
exit:
AIKIT_UnInit();
}
注意
3.尝试运行代码,观察是否有报错
在调试的过程中,我们的主代码
int main() {
TestIVW();
return 0;
}
出现报错
报错找不到资源
解决方法
将aiui_add_awak的resource文件夹复制到bin_x64
分析
当资源文件夹放置在运行代码的同级目录下时,代码可以更轻松地找到并加载这些资源文件。这是因为代码通常会在当前工作目录中查找资源文件。默认情况下,代码在没有明确指定路径的情况下会在当前工作目录中搜索资源文件。如果资源文件位于代码所在的同级目录下,那么代码可以直接找到并加载这些文件。
而当资源文件夹放置在其他位置时,代码可能无法准确地找到资源文件所在的路径,从而导致无法加载这些文件,进而引发错误。通过将资源文件夹放置在与运行代码同级的目录下,提供了一个更直接的路径,使得代码可以成功找到并加载这些资源文件,从而解决了报错问题。
(4)添加aiui和wake的代码逻辑
目标:通过唤醒词“你好智慧机器人”唤醒aiui功能。
1.main
2.修改唤醒结果
找到OnOutput()函数
string temp = (char*)output->node->value;
createAgent();
start();
wakeup();
if (temp.find("你好小迪") != string::npos)
{
printf("----触发你好小迪,拦截----\n");
return;
}
printf("OnOutput abilityID :%s\n", handle->abilityID);
printf("OnOutput key:%s\n", output->node->key);
printf("OnOutput value:%s\n", (char*)output->node->value);
createAgent();
start();
wakeup();
writeAudio();
AIUI_SLEEP(10000);
stopAudio();
代码分析
四、查看效果
五、总结
五、相关文章推荐
上面有一些技术问题推荐查看这些文章(如有侵权,告知必删)
ros语音识别实现:http://t.csdnimg.cn/KVSYS
Shell脚本简单学习:http://t.csdnimg.cn/PzjlL
CMake简单学习: http://t.csdnimg.cn/165au
ROS简单学习: http://t.csdnimg.cn/a7Vpf
简单学习语音唤醒: http://t.csdnimg.cn/SJAnt