前阵子朋友的毕业设计让我来帮他完成,本来自己手里项目已经够多,但是关系太铁,就帮他做了(其实就是他太菜),项目主要包含两个模块,微信小程序+单片机实现蓝牙控制灯的开关,微信小程序中设计的主要是语音识别模块,对用户输入的语音进行识别,后台采用的SpringBoot单机项目,判断关键字,然后向蓝牙发送信息,再到单片机以实现灯光的控制,看着很容易实现,但是里边的坑实在太多了,我本身是Java后台开发,但是技多不压身呐,抽空就多学一点,不闲扯了,进入正题。
语音识别采用的是百度语音,具体如何申请,自行百度获取,这里主要说的就是百度语音支持的语音类型,包括pcm和wav格式,因为小程序录音之后是mp4格式,所以在录音完毕之后,需要上传到后台服务器进行mp4->wav、pcm转码,这个坑有点大。
1)首先百度语音appid及密钥自行获取,是免费版的,注意选择语音识别类型
public static final String APP_ID = "";
public static final String API_KEY = "";
public static final String SECRET_KEY = "";
//添加依赖
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.1.0</version>
</dependency>
2)获取小程序传来的mp3文件,并且转换成pcm流,然后获取字节数组
@RequestMapping(value = "/speechRecognition")
public Object speechReco(HttpServletRequest request) {
MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
try {
byte[] pcmBytes = mp3Convertpcm(file.getInputStream());
//向百度语音接口发送请求
JSONObject resultJson = speechBdApi(pcmBytes);
if (null != resultJson && resultJson.getInt("err_no") == 0) {
return resultJson.getJSONArray("result").get(0).toString().split(",")[0];
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public byte[] mp3Convertpcm(InputStream mp3Stream) throws Exception {
//MP3文件获取输入流AudioInputStream
AudioInputStream mp3audioStream = AudioSystem.getAudioInputStream(mp3Stream);
// 将AudioInputStream MP3 流 转为PCM AudioInputStream mp3->pcm
AudioInputStream pcmaudioStream = AudioSystem.getAudioInputStream(AudioFormat.Encoding.PCM_SIGNED,
mp3audioStream);
//读流操作,输出字节数组
byte[] pcmBytes = read(pcmaudioStream);
pcmaudioStream.close();
mp3audioStream.close();
return pcmBytes;
}
语音识别模块相对简单,需要注意的坑就是mp3转pcm,搞得我头好大,
1)首先是页面加载函数,微信小程序授权录音
onLoad: function (options) {
var a = this;
wx.authorize({
scope: "scope.record",
success: function () {
console.log("录音授权成功");
},
fail: function () {
console.log("录音授权失败");
}
}), a.onShow()
}
2)绑定按钮长按事件
recordStart: function (e) {
var n = this;
rm.start({
format: "mp3",
sampleRate: 32e3,
encodeBitRate: 192e3
}), n.setData({
touchStart: e.timeStamp,
isTouchStart: true,
isTouchEnd: false,
showPg: true,
})
3)录音结束事件
recordTerm: function (e) {
rm.stop(), this.setData({
isTouchEnd: true,
isTouchStart: false,
touchEnd: e.timeStamp,
showPg: false,
value: 100
}), clearInterval(this.timer);
}
4)录音结束之后,会自动保存到临时文件夹中,录音结束调取上传mp3文件函数
//录音停止时调用
rm.onStop(function (e) {
var a = this;
wx.showLoading({
title: "正在识别..."
});
//上传逻辑
var n = {
url: "ip地址信息",
filePath: e.tempFilePath,
name: "file",
header: {
"Content-Type": "application/json"
},
success: function (res) {
}
};
wx.uploadFile(n);
})
检查蓝牙是否打开–>检查蓝牙状态–>获取蓝牙设备列表–>匹配指定蓝牙deviceId–>获取指定蓝牙服务–>获取已连接蓝牙得特征值–>发送数据
以上就是发送蓝牙的所有步骤,具体代码太多就不贴出来了,注意需要在真机上进行测试否则必定失败,项目地址在下方连接。
1、因为之前不怎么写小程序,所以对回掉函数不怎么了解,this关键字在回掉函数内无法使用,需要使用外部变量的时候需要在app外生命var that = this;方可调用。
2、流的转换,在mp3转pcm时有个流的对应转换需要注意,一是HttpServletReqest转MultipartHttpServletRequest时会有异常,二是InputStream转AudioInputStream时也会有异常,使用项目里的代码是没有问题的。
多去挑战一些没有做过的东西,看似简单,实则坑个数量要远远多于想法的数量。
GitHub地址: