公司要在微信小程序上面实现语音识别的功能,后端的踩坑功能就落到了个人头上了。本着好好学习,努力研究的精神,二话不说就接下了这个任务了。
我在公司的开发环境是在Window上面的,而生产环境是在Ubuntu上面的,因此有的时候开发出来的东西会有一点兼容的问题,这个见怪不怪了。在Window环境上面研究的过程当中规中矩,没有碰到上面太多或者太大的坑。下面先说一下实现的大概思路,接着在说一下遇到的坑。
咱们是在微信的小程序上面调用微信的录音接口,把录音上传到咱们后端进行处理,咱们后端接收到微信小程序传回来的语音文件,这个语音文件是SILK格式的,咱们收到SILK格式的文件后,先要将SILK文件转换为WAV格式或者PCM(音频采样率要是 16k 或者 8k,16 位,单声道音频),在文件转换成功后,而后调用讯飞的语音识别的接口,把语音转换为文字的格式,而后使用这个文字进行相对应的逻辑操做。
微信用的SILKv3编码是Skype向第三方开发人员和硬件制造商提供免版税认证(RF)的Silk宽带音频编码器,Skype后来将其开源。反正录音的文件很小,发回来的都是几K的,转换为PCM或者WAV都是100K左右。下面说一下遇到的坑和爬坑过程:
坑一:libmsc64.so文件不生效。花费了一天的时间看文档那些,已经在Window上面把总体的流程跑通了,程序的识别率仍是挺高的,接下来要作的是把这个程序配置到测试服务器上面,看能不能给前端的小程序跑通。由于讯飞的服务要用到动态库的,而在Window上面的动态库能够直接放到项目的根目录或者System32 目录,可是Ubuntu要本身手动指定LD_LIBRARY_PATH的目录,虽然以前Linux系统用了好久,可是只是一些基础得操做,LD_LIBRARY_PATH这个以前是没有搞过。。。,百度了很久,按照百度的教程配置了一下,发现配置成功了,可是程序却死活说缺包,实在不行,因此我就把libmasc64.so文件放到/lib/ 和 /lib64/ 目录,发现也不行,打印了一些动态库的地址,/lib/ 和 /lib64/ 目录是有配置了的,能够直接把so文件放进去的,很无奈,搞了半天,死活不生效,测试服上面有不少东西,是不能重启的。最后只能在代码里面执行System.load(/xxxx/libmac64.so),这样把文件加载进去,这个是没有办法的办法。html
坑二:语音转换功能public static void RecognizePcmfileByte(String uuid,String filePath)功能要在讯飞的注册SpeechUtility.createUtility(“appid=” + APPID) 成功后才能只能,否则也会报错,大概的意思是缺动态库包,因此我把讯飞的注册功能在在项目运行的ServletContentListener里面,这样就能够保在调用转换语音功能前必定注册成功了。前端
坑三:微信小程序文件上传BUG,由于这个BUG是微信的锅,可是也影响到了咱们功能的实现了,在咱们把功能实现差很少了,前端也把小程序的文件上传上来了,识别率仍是不错的,在咱们接受的范围内,而后我就用个人手机扫码尝鲜一下,却发现预定文件上传失败,说是上传的文件为空。这个问题就很怪了,咱们刚刚才在其余的手机上面测试是没有什么问题的,在我这里却又问题,难道是个人信仰有问题?试了多部手机才发现:在IPhone上面微信的上传文件是没有什么问题的,可是在Android上面上传文件是不行的,IPhone上面最新的微信是6.5多,Android的最新版本是6.3多,因此上传文件有问题,百度了一下,不少人都有这个问题【咱们上传文件是直接用File上传的,尚未试过把文件转为base64再上传】
坑四:讯飞识别率低的问题。咱们在拿到微信的文件后,是经过ffmpeg来进行转码的,转码的功能我是参考了这个开源项目https://github.com/kn007/silk-v3-decoder进行转换的,该项目是用到了Ffmpeg和Gcc,他在转换的脚本里面linux
#!/bin/bash # File: converter.sh # Date: August 19th, 2016 # Time: 18:56:52 +0800 # Author: kn007 <kn007@126.com> # Blog: https://kn007.net # Link: https://github.com/kn007/silk-v3-decoder # Usage: sh converter.sh silk_v3_file/input_folder output_format/output_folder flag(format) # Flag: not define ---- not define, convert a file # other value ---- format, convert a folder, batch conversion support # Requirement: gcc ffmpeg # Colors RED="\e[31;1m" GREEN="\e[32;1m" YELLOW="\e[33;1m" WHITE="\e[37;1m" RESET="\e[0m" # Main cur_dir=$(cd `dirname $0`; pwd) if [ ! -r "$cur_dir/silk/decoder" ]; then echo -e "${WHITE}[Notice]${RESET} Silk v3 Decoder is not found, compile it." cd $cur_dir/silk make && make decoder [ ! -r "$cur_dir/silk/decoder" ]&&echo -e "${RED}[Error]${RESET} Silk v3 Decoder Compile False, Please Check Your System For GCC."&&exit echo -e "${WHITE}========= Silk v3 Decoder Compile Finish =========${RESET}" fi cd $cur_dir while [ $3 ]; do pidof /usr/bin/ffmpeg&&echo -e "${RED}[Error]${RESET} ffmpeg is occupied by another application, please check it."&&exit [ ! -d "$1" ]&&echo -e "${RED}[Error]${RESET} Input folder not found, please check it."&&exit TOTAL=$(ls $1|wc -l) [ ! -d "$2" ]&&mkdir "$2"&&echo -e "${WHITE}[Notice]${RESET} Output folder not found, create it." [ ! -d "$2" ]&&echo -e "${RED}[Error]${RESET} Output folder could not be created, please check it."&&exit CURRENT=0 echo -e "${WHITE}========= Batch Conversion Start ==========${RESET}" ls $1 | while read line; do let CURRENT+=1 $cur_dir/silk/decoder "$1/$line" "$2/$line.pcm" > /dev/null 2>&1 if [ ! -f "$2/$line.pcm" ]; then ffmpeg -y -i "$1/$line" "$2/${line%.*}.$3" > /dev/null 2>&1 & ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 [ -f "$2/${line%.*}.$3" ]&&echo -e "[$CURRENT/$TOTAL]${GREEN}[OK]${RESET} Convert $line to ${line%.*}.$3 success, ${YELLOW}but not a silk v3 encoded file.${RESET}"&&continue echo -e "[$CURRENT/$TOTAL]${YELLOW}[Warning]${RESET} Convert $line false, maybe not a silk v3 encoded file."&&continue fi ffmpeg -y -f s16le -ar 24000 -ac 1 -i "$2/$line.pcm" "$2/${line%.*}.$3" > /dev/null 2>&1 & ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 rm "$2/$line.pcm" [ ! -f "$2/${line%.*}.$3" ]&&echo -e "[$CURRENT/$TOTAL]${YELLOW}[Warning]${RESET} Convert $line false, maybe ffmpeg no format handler for $3."&&continue echo -e "[$CURRENT/$TOTAL]${GREEN}[OK]${RESET} Convert $line To ${line%.*}.$3 Finish." done echo -e "${WHITE}========= Batch Conversion Finish =========${RESET}" exit done $cur_dir/silk/decoder "$1" "$1.pcm" > /dev/null 2>&1 if [ ! -f "$1.pcm" ]; then ffmpeg -y -i "$1" "${1%.*}.$2" > /dev/null 2>&1 & ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 [ -f "${1%.*}.$2" ]&&echo -e "${GREEN}[OK]${RESET} Convert $1 to ${1%.*}.$2 success, ${YELLOW}but not a silk v3 encoded file.${RESET}"&&exit echo -e "${YELLOW}[Warning]${RESET} Convert $1 false, maybe not a silk v3 encoded file."&&exit fi ffmpeg -y -f s16le -ar 24000 -ac 1 -i "$1.pcm" "${1%.*}.$2" > /dev/null 2>&1 ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 rm "$1.pcm" [ ! -f "${1%.*}.$2" ]&&echo -e "${YELLOW}[Warning]${RESET} Convert $1 false, maybe ffmpeg no format handler for $2."&&exit echo -e "${GREEN}[OK]${RESET} Convert $1 To ${1%.*}.$2 Finish." exit
批量脚本的执行命令:sh converter.sh input ouput wav
单个转换脚本:sh converter.sh input wav
上面的脚本开源直接转换单个文件,也能够批量转换一个文件夹,可是他单个转换的执行命令只能指定文件输入的目录,不能指定文件输出的的文件,因此我根据他的脚步修改一下脚本的:ios
#!/bin/bash # File: converter.sh # Date: August 19th, 2016 # Time: 18:56:52 +0800 # Author: kn007 <kn007@126.com> # Blog: https://kn007.net # Link: https://github.com/kn007/silk-v3-decoder # Usage: sh converter.sh silk_v3_file/input_folder output_format/output_folder flag(format) # Flag: not define ---- not define, convert a file # other value ---- format, convert a folder, batch conversion support # Requirement: gcc ffmpeg # Colors RED="\e[31;1m" GREEN="\e[32;1m" YELLOW="\e[33;1m" WHITE="\e[37;1m" RESET="\e[0m" # Main cur_dir=$(cd `dirname $0`; pwd) echo ===${cur_dir} if [ ! -r "$cur_dir/silk/decoder" ]; then echo -e "${WHITE}[Notice]${RESET} Silk v3 Decoder is not found, compile it." cd $cur_dir/silk make && make decoder [ ! -r "$cur_dir/silk/decoder" ]&&echo -e "${RED}[Error]${RESET} Silk v3 Decoder Compile False, Please Check Your System For GCC."&&exit echo -e "${WHITE}========= Silk v3 Decoder Compile Finish =========${RESET}" fi cd $cur_dir echo 输入文件: $1 echo 输出文件: $2 echo 输出格式: $3 pidof /usr/bin/ffmpeg&&echo -e "${RED}[Error]${RESET} ffmpeg is occupied by another application, please check it."&&exit [ ! -f "$1" ]&&echo -e "${RED}[Error]${RESET} Input file not found, please check it."&&exit TOTAL=$(ls $1|wc -l) # [ ! -f "$2" ]&&echo -e "${WHITE}[Notice]${RESET} Output file not found."&&exit $cur_dir/silk/decoder "$1" "$2.pcm" > /dev/null 2>&1 if [ ! -f "$2.pcm" ]; then ffmpeg -y -i "$1" "$2.$3" > /dev/null 2>&1 & ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 fi ffmpeg -y -f s16le -ar 16000 -ac 1 -i "$2.pcm" "$2.$3" > /dev/null 2>&1 & ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 # 删除中间pcm文件 # rm "$2.pcm" echo -e "输出文件:$2.$3" echo -e "${WHITE}========= Conversion Finish =========${RESET}" exit
若是我再linux上面执行sh converter.sh input wav 这样就能够直接指定输入输出文件的目录
可是有一个问题,用个人脚本会输出两个文件,一个是xx.pcm,一个是xx.wav文件,我听了一下wav文件,发现是没有什么问题的,识别率也不会不好,可是pcm文件的识别率就有问题了,由于上面的脚本根本没有把pcm文件转换为采样率要是 16k 或者 8k,16 位,单声道音频的文件,因此识别率很低,可是wav转换为了符合要求的格式,用wav转码仍是不错的,我是用了这里没有符合要求的pcm识别率才这么低的。
后来找了一些资料,发现一位大哥有过相关的研究了,地址为:http://www.iosre.com/t/topic/3199 参考了上面的执行转码命令,把转码的脚本修改成
#!/bin/bashgit
# File: converter.sh # Date: August 19th, 2016 # Time: 18:56:52 +0800 # Author: kn007 <kn007@126.com> # Blog: https://kn007.net # Link: https://github.com/kn007/silk-v3-decoder # Usage: sh converter.sh silk_v3_file/input_folder output_format/output_folder flag(format) # Flag: not define ---- not define, convert a file # other value ---- format, convert a folder, batch conversion support # Requirement: gcc ffmpeg # Colors RED="\e[31;1m" GREEN="\e[32;1m" YELLOW="\e[33;1m" WHITE="\e[37;1m" RESET="\e[0m" # Main cur_dir=$(cd `dirname $0`; pwd) echo ===${cur_dir} if [ ! -r "$cur_dir/silk/decoder" ]; then echo -e "${WHITE}[Notice]${RESET} Silk v3 Decoder is not found, compile it." cd $cur_dir/silk make && make decoder [ ! -r "$cur_dir/silk/decoder" ]&&echo -e "${RED}[Error]${RESET} Silk v3 Decoder Compile False, Please Check Your System For GCC."&&exit echo -e "${WHITE}========= Silk v3 Decoder Compile Finish =========${RESET}" fi cd $cur_dir echo 输入文件: $1 echo 输出文件: $2 echo 输出格式: $3 pidof /usr/bin/ffmpeg&&echo -e "${RED}[Error]${RESET} ffmpeg is occupied by another application, please check it."&&exit [ ! -f "$1" ]&&echo -e "${RED}[Error]${RESET} Input file not found, please check it."&&exit TOTAL=$(ls $1|wc -l) # [ ! -f "$2" ]&&echo -e "${WHITE}[Notice]${RESET} Output file not found."&&exit $cur_dir/silk/decoder "$1" "$2.pcm" > /dev/null 2>&1 if [ ! -f "$2.pcm" ]; then ffmpeg -y -i "$1" "$2.$3" > /dev/null 2>&1 & ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 fi #ffmpeg -y -f s16le -ar 16000 -ac 1 -i "$2.pcm" "$2.$3" > /dev/null 2>&1 & ffmpeg -f s16le -ar 12k -ac 2 -i "$2.pcm" -f wav -ar 16k -ac 1 "$2.$3" > /dev/null 2>&1 & ffmpeg_pid=$! while kill -0 "$ffmpeg_pid"; do sleep 1; done > /dev/null 2>&1 # 删除中间pcm文件 # rm "$2.pcm"
echo -e “输出文件:$2.
{WHITE}========= Conversion Finish =========${RESET}”
exit
执行命令改成:sh converter.sh input wav
这样识别率真的是不错的,多谢上面两位大哥帮忙的分享,这样识别率就很不错了。
后面可能还会有坑,打算用讯飞的私有语义实现功能,可是私有语义还在申请中,坑爹。暂时坑就怎么多了。
踩坑的过程要保持一个好的心态,坚持住,不要要哭,遇到坑,有时候睡一觉就会发现问题了。github