GEC6818科大讯飞离线语音识别
文章目录
- GEC6818科大讯飞离线语音识别
- 一、 下载科大讯飞离线语音SDK
- 二、 解压文件夹后
- 三、与GEC6818开发板一起使用
- 3.1 使用科大讯飞的离线语音在ubantu中运行,作为服务端进行关键字的识别
- 3.2 call.bnf-->hehe.bnf
- 3.3 asr_offine_sample.c文件修改
一、 下载科大讯飞离线语音SDK
在下载SDK时需要注意选择Linux的版本!!
在官网下载离线语音的包,解压后可以得到下面的一些文件夹:
二、 解压文件夹后
解压后你需要知道自己命令放在下面的文件夹中
关于Make file文件:
关于asr_offline_sample.c文件:
asr_offline_sample.c
文件是我们更改为自己的逻辑的文件,但是也不需要都了解清楚只要会改就行。
更改完asr_offline_sample.c
文件后,在ubantu里面运行makefile文件后会有一些警告,这些都是定义的问题,可以不用管,但是在./asr_offline_sample
运行的时候会报错找不到库,所以我们需要将资料包里面文件复制到lib目录下,具体如下:
需要移动的文件:
执行命令:
cp ./libmsc.so /lib
注意前面的`./libmsc.so`是相对路径,可以根据自己的当前路径进行更改,后面是移动到根目录下的lib目录下。
然后再执行就不会报错了。
三、与GEC6818开发板一起使用
3.1 使用科大讯飞的离线语音在ubantu中运行,作为服务端进行关键字的识别
需要更改的重要的两个文件就是bin/call.bnf
和samples/asr_offine_sample/asr_offine_sample.c
.这两个文件,第一个文件是修改我们需要识别的字眼,第二个文件是C 语言代码,可以在官方的基础上修改为自己所需要的逻辑
3.2 call.bnf–>hehe.bnf
我自己将官方自带的call.bnf复制了一份修改名字为hehe.bnf,在新的基础上进行的修改,更改了这个文件后,需要在后面的例程中的.c文件中修改这个文件。
例如:
注意我们这里使用对应的ID是非常重要的,因为我后后续进行语音识别后就是根据这个ID来判断识别到的内容,然后在执行相应的操作。
3.3 asr_offine_sample.c文件修改
上面有提到过的修改了离线语法文件后在.c文件中也需要修改相应的文件名
修改后的代码–当然也可以不用这样大幅度的修改,只是将官方的代码进行了规整。
//服务器
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "asr_offline_sample.h" //科大讯飞
//全局的套接字
int sockfd = -1;
//将套接字创建好 并且绑定 监听
//将ip地址和端口号传进来 端口号释放需要时间(轮询机制)
void TcpInit(const char * ipaddr,unsigned short port)
{
//1 创建套接字 ---- 神马都是文件,因此你的网络通信也是一个文件
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("server socket error");
exit(1);//没有必要运行了
}
//2 我们需要将服务器的IP地址绑定到套接字
struct sockaddr_in sa;
sa.sin_family = AF_INET;//协议族
sa.sin_port = htons(port);//端口号 内存是小端的 我们要转大端
sa.sin_addr.s_addr = inet_addr(ipaddr);//将我们点分式的ip地址转换为一个大端整数
//printf("ipaddr = %x port = %x\n",inet_addr(ipaddr),htons(port));
int r = bind(sockfd,(struct sockaddr *)&sa,sizeof(sa));
if(-1 == r)
{
perror("server bind error");
exit(2);//没有必要运行了
}
//3 监听连接 ---- 创建一个监听队列 建立5个10个可以了
listen(sockfd,5);
}
//接收客户端发过来的文件内容
void SaveFile(int accceptfd,int filesize)
{
//每一次都是重复的覆盖hehe.pcm
int fd = open("wav/hehe.pcm",O_RDWR | O_TRUNC|O_CREAT,0644);//截短这个文件
if(-1 == fd)
{
send(accceptfd,"error!!!",9,0);//失败发送这个错误
return;
}
send(accceptfd,"next!!!!",9,0);//发送下一步的指令
unsigned char buf[1024] = {0};
int size = 0;
//接收文件的内容
while(1)
{
int r = recv(accceptfd,buf,1024,0);
if(-1 == r)
{
perror("recv error");
break;
}
else if(0 == r)//客户端已经断了
{
printf("对方断开连接了\n");
break;
}
else//接收到信息了
{
//将文件的内容写入到文件
write(fd,buf,r);
//做完之后要退出
size += r;
if(size >= filesize)
break;
}
}
close(fd);
}
//专门用于去服务一个客户的线程
void * ClinetFunction(void * arg)
{
pthread_detach(pthread_self());//将其分离
int * accceptfd = (int *)arg;
printf(" * accceptfd = %d\n", * accceptfd);
int filesize = 0;
//你发什么信息过来 我就在这个信息之前加上一节 然后回发给你
while(1)
{
printf("\t\t等待客户端传文件过来........\n");
int r = recv(*accceptfd,&filesize,4,0);//阻塞等待数据过来
if(-1 == r)
{
perror("recv error");
break;
}
else if(0 == r)//客户端已经断了
{
printf("对方断开连接了\n");
break;
}
else//接收到信息了
{
//文件大小
SaveFile(* accceptfd,filesize);
int id = GetFlayId();//文件接收完毕 那么我们就放过去识别即可
//给客户端返回id
send(* accceptfd,&id,4,0);
}
}
close(*accceptfd);
free(accceptfd);
return NULL;
}
//等待客户端的连接
void waitconnect(void)
{
//我们要基于这个连接套接字去通信
struct sockaddr_in sa;
socklen_t addrlen = sizeof(sa);
while(1)
{
printf("一直等待对方的连接.......\n");
int * accceptfd = malloc(4);//避免释放 因此我们要动态内存分配才可以
*accceptfd = accept(sockfd,(struct sockaddr *)&sa,&addrlen);
printf("连接者为:%s %d\n",inet_ntoa(sa.sin_addr),ntohs(sa.sin_port));
//开一个线程出去 让它去服务与我的连接
pthread_t thread;
if(pthread_create(&thread,NULL,ClinetFunction,(void *)accceptfd) != 0)
{
perror("create thread error");
continue;
}
}
close(sockfd);
}
//通过main函数的参数 我们将这个ip地址和端口给进去
//./a.out 192.168.31.251 8888
int main(int argc,char * argv[])
{
if(argc < 3)
{
printf("参数都不齐\n");
return -1;
}
//初始化科大讯飞的库
FlayInit();
TcpInit(argv[1],atoi(argv[2]));
waitconnect();
return 0;
}
完整的工程大家可以在我的gitee上进行下载
下载地址:GEC6818智能语音家居系统