小程序语音与讯飞语音识别踩坑过程

公司要在微信小程序上面实现语音识别的功能,后端的踩坑功能就落到了个人头上了。本着好好学习,努力研究的精神,二话不说就接下了这个任务了。
我在公司的开发环境是在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. 3 &quot; e c h o e &quot; 3&quot; echo -e &quot; {WHITE}========= Conversion Finish =========${RESET}”
exit
执行命令改成:sh converter.sh input wav
这样识别率真的是不错的,多谢上面两位大哥帮忙的分享,这样识别率就很不错了。
后面可能还会有坑,打算用讯飞的私有语义实现功能,可是私有语义还在申请中,坑爹。暂时坑就怎么多了。
踩坑的过程要保持一个好的心态,坚持住,不要要哭,遇到坑,有时候睡一觉就会发现问题了。github