点击蓝色字关注我们!
一个努力中的公众号
长的好看的人都关注了
本文主要讲解 小程序开发-音频录音播放以及语音识别,文章很长 但都是干货、市面上语音识别 大部分只支持pcm、wma,只有腾讯支持mp3 但是XX文档能力十分拉基,需要花费时间才能读懂 所以本文使用百度AI语音识别
第一步 创建录音页面文件
在app.js文件中添加录音页面,然后保存会自动生成record文件
record页面文件图如下
第二步 record.wxml 页面代码
<!--pages/record/record.wxml-->
<!-- 录音 -->
<view class='record-login' catch:longpress="sayVideo"
catch:touchmove="handleTouchMove"
catch:touchend="sayVideoEnd">
<image src='../../images/operation/record.png' mode="widthFix">
</image>
</view>
record.png 图片
第三步 record.wxss css代码
/* pages/record/record.wxss */
.record-login {
display: block;
margin-left: auto;
margin-right: auto;
padding-left: 1rem;
padding-right: 1rem;
box-sizing: border-box;
font-size: 18px;
text-align: center;
text-decoration: none;
border-radius: 1rem;
-webkit-tap-highlight-color: transparent;
overflow: hidden;
color: #000;
background-color: #f8f8f8;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
}
.record-login image {
width: 2rem;
height: 3rem;
}
第四步 record.js 页面的方法(重点)
// pages/record/record.js
//录音管理
import api from '../../utils/config/urlConfig.js';
const recorderManager = wx.getRecorderManager()
//音频组件控制
const innerAudioContext = wx.createInnerAudioContext()
//创建audio控件
const myaudio = wx.createInnerAudioContext();
const app = getApp()
//语音识别
Page({
/**
* 页面的初始数据
*/
data: {
//授权状态
status: 1,
//录音变量
tempFilePath: "",
//是否发生
send: true,
//触摸点的坐标信息
startPoint: [],
},
// ----------------------------------- 录音
//按住说话
sayVideo: function(e) {
var that = this;
this.setData({
send: true,//长按时应设置为true,为可发送状态
startPoint: e.touches[0],//记录触摸点的坐标信息
})
const options = {
duration: 60000,//指定录音的时长,单位 ms
sampleRate: 16000,//采样率
numberOfChannels: 1,//录音通道数
encodeBitRate: 96000,//编码码率
format: 'm4a',//音频格式,有效值 aac/mp3
frameSize: 50,//指定帧大小,单位 KB
};
//如果状态不为2 那么表示没有授权
if (this.data.status != 2) {
//没有授权
wx.authorize({
scope: 'scope.record',
success() {
console.log("录音授权成功");
//第一次成功授权后 状态切换为2
that.setData({
status: 2,
})
},
fail() {
wx.openSetting({
success: (res) => {
console.log(res.authSetting);
if (!res.authSetting['scope.record']) {
//未设置录音授权
console.log("未设置录音授权");
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: false,
success: function (res) { },
});
} else {
//第二次才成功授权
console.log("设置录音授权成功");
that.setData({
status: 2,
})
recorderManager.start(options);
}
},
fail: function () {
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: false,
success: function (res) { },
});
}
})
}
});
} else {
recorderManager.start(options);
}
},
//松开
sayVideoEnd: function (e) {
//先停止录音
recorderManager.stop();
var that = this;
//判断是否需要上传
if (this.data.send){
//监听录音停止的事件
recorderManager.onStop((res) => {
if (res.duration < 1000) {
wx.showModal({
title: '提示',
content: '录音时间太短',
showCancel: false,
success: function (res) { },
});
return;
} else {
//查询录音的数据
console.log(res.tempFilePath);
innerAudioContext.autoplay = true
innerAudioContext.src = res.tempFilePath,
innerAudioContext.onPlay(() => {
console.log('开始播放')
})
innerAudioContext.onError((res) => {
})
// 文件临时路径
var tempFilePath = res.tempFilePath;
//转换格式 默认silk后缀
var temp = tempFilePath.replace('.m4a', '');
app.fileReq('你后端接口路径', tempFilePath, '参数',
function (res) {
console.log(res);
}
) }
});
this.setData({
send: true//设置为发送语音
})
}
},
//滑动取消
handleTouchMove: function (e) {
//计算距离,当滑动的垂直距离大于25时,则取消发送语音
if (Math.abs(e.touches[e.touches.length - 1].clientY -
this.data.startPoint.clientY) > 5) {
this.setData({
send: false//设置为不发送语音
})
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
//设置页面title
wx.setNavigationBarTitle({
title: '测验'
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function (res) {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
} else {
console.log("来自右上角转发菜单")
}
return {
title: 'EgoEnglish',
path: '/pages/login/loigin',
imageUrl: "/images/login/wechat.png",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
},
})
第四步 Java后端文件上传
文件上传代码如下
注:需引入百度的Api Jar maven方式如下
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.4.0</version>
</dependency>
阿里的JSON Jar
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
packagecom.demo.api.service.impl;
importjava.io.File;
importjava.text.SimpleDateFormat;
importjava.util.Arrays;
importjava.util.Date;
importjava.util.List;
importjavax.annotation.Resource;
importjavax.servlet.http.HttpServletRequest;
importorg.apache.commons.io.FileUtils;
importorg.springframework.stereotype.Service;
importorg.springframework.web.multipart.MultipartFile;
importcom.haithink.api.service.ApiFileService;
importcom.haithink.base.common.utils.ReturnResult;
importcom.haithink.base.common.utils.Status;
importcom.haithink.base.util.LogUtils;
importcom.haithink.thirdParty.BaiDuVoiceDiscernService;
/**
* @author 作者: tutu
* @version 创建时间:2019年10月25日 下午7:57:16
* @explain 类说明 微信文件上传类接口实现类
*/
@Service
publicclassApiFileServiceImpl implementsApiFileService {
@Resource
privateBaiDuVoiceDiscernService service;
/**
* 文件上传路径
*/
privatefinalString uploadPath = "F:\\demo\\小程序\\" + newSimpleDateFormat("yyyy-MM-dd").format(newDate()).toString() + "\\m4a";
/**
* 文件上传-上传录音
* @param request
* @param uploadFile ---录音文件
* @return
*/
@Override
publicReturnResult record(HttpServletRequest request, MultipartFile uploadFile) {
ReturnResult result = newReturnResult();
try{
// 如果目录不存在就创建
File uploadDir = newFile(uploadPath);
if(!uploadDir.exists()) {
uploadDir.mkdir();
}
// 获取文件的 名称.扩展名
String oldName = uploadFile.getOriginalFilename();
String extensionName = "";
// 获取原来的扩展名
if((oldName != null) && (oldName.length() > 0)) {
intdot = oldName.lastIndexOf('.');
if((dot > -1) && (dot < (oldName.length() - 1))) {
extensionName = oldName.substring(dot);
}
}
// 构建文件名称
String fileName = System.currentTimeMillis() + "_" + System.nanoTime()
;
//定义文件类型变量
String[] fileType = { ".CD", ".WAVE", ".AIFF", ".AU", ".MPEG", ".MP3",
".MPEG-4", ".MIDI", ".WMA", ".RealAudio", ".VQF", ".OggVorbis",
".AMR",".pcm", ".m4a" };
//存储文件类型
List<String> fileTyepLists = Arrays.asList(fileType);
//循环类型次数
intfileTypeOnCount = 0;
for(String fileTyepListss : fileTyepLists) {
if(fileTyepListss.equalsIgnoreCase(extensionName)) {
// -----如果是音频文件的话
// 构建文件路径
String filePath = uploadPath + File.separator + fileName + extensionName;
// 保存文件
try{
FileUtils.writeByteArrayToFile(newFile(filePath), uploadFile.getBytes());
} catch(Exception e) {
e.printStackTrace();
}
} else{
fileTypeOnCount++;
}
}
//如果循环类型次数等于全部文件类型,那么该文件不是音频文件
if(fileTypeOnCount == fileTyepLists.size()) {
result.setStatus(Status.UNKNOWN);
result.setMsg("不是音频文件");
returnresult;
}
//上传成功
result.setStatus(Status.SUCCESS);
result.setMsg("成功");
returnresult;
} catch(Exception e) {
LogUtils.COMMON.error("文件上传-上传录音 error:", e);
result.setStatus(Status.FAIL);
result.setMsg("上传失败");
returnresult;
}
}
}
百度语音接口
首先 搜索百度语音选择第一个
选择语音识别,点进来以后 点击立即使用,创建一个项目,记好AppID 、API Key、 Secret Key,剩下的就不在这里多做介绍,大家可自行学习。
接下来就是接口对接
package com.demo.thirdParty;
import java.io.File;
import java.io.FileInputStream;
import java.util.Base64;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import com.haithink.base.util.LogUtils;
import com.haithink.common.util.StringUtil;
import com.haithink.utils.GsonUtils;
import com.haithink.utils.OkHttpUtils;
/**
* @author 作者: tutu
* @version 创建时间:2019年10月25日 下午7:57:16
* @explain 类说明
*/
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class BaiDuVoiceDiscernService {
/**
* url , Token的url,http可以改为https
*/
private static final String oauthUrl = "http://openapi.baidu.com/oauth/2.0/token";
private static final String url = "http://vop.baidu.com/server_api";
// 填写网页上申请的appkey 如 $apiKey="g8eBUMSokVB1BHGmgxxxxxx"
private final String APP_KEY = "";
// 填写网页上申请的APP SECRET 如 $SECRET_KEY="94dc99566550d87f8fa8ece112xxxxx"
private final String SECRET_KEY = "";
// 文件格式, 支持pcm/wav/amr 格式,极速版额外支持m4a 格式
private final String format = "m4a";
private String CUID = "1234567JAVA";
// 采样率固定值
private final int RATE = 16000;
/**
* dev_pid 语音识别模板
*/
private int DEV_PID = 1737;
/**
* 保存访问接口获取的token
*/
private String token;
/**
* 获取百度语音识别tocken
*/
public String getTocken() {
// 封装获取tocken的url
String getTokenURL = oauthUrl + "?grant_type=client_credentials" + "&client_id=" + GsonUtils.urlEncode(APP_KEY)
+ "&client_secret=" + GsonUtils.urlEncode(SECRET_KEY);
try {
JsonObject retJson = OkHttpUtils.doGetRetJson(getTokenURL);
// 如果返回结果有tocken
if (StringUtil.isNotEmpty(retJson.get("access_token"))) {
// 返回tocken
return retJson.get("access_token").getAsString();
} else {
throw new Exception("获取tocken error");
}
} catch (Exception e) {
LogUtils.COMMON.error("获取tocken error");
return "";
}
}
/**
* 语音识别
*
* @param tocken --- 百度tocken
* @param file --- 文件file
*/
public JsonObject voiceDiscern(String tocken, File file) {
try {
// 先进行文件转byte
byte[] content = getFileContent(file);
// 将byte转为base格式字符串
Base64.Encoder encoder = Base64.getEncoder();
// 定义请求参数
JSONObject params = new JSONObject();
String speech = encoder.encodeToString(content);
params.put("dev_pid", DEV_PID);
// params.put("lm_id",LM_ID);//测试自训练平台需要打开注释
params.put("format", format);
params.put("rate", RATE);
params.put("token", token);
params.put("cuid", CUID);
params.put("channel", "1");
params.put("len", content.length);
params.put("speech", speech);
//返回识别结果
return OkHttpUtils.doPostRetJson(url, params.toJSONString());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将文件转为byte
*
* @param file 文件file
* @return
*/
private byte[] getFileContent(File file) {
FileInputStream is = null;
byte[] content = null;
try {
// 先判断文件是否存在
if (!file.canRead()) {
System.err.println("文件不存在或者不可读: " + file.getAbsolutePath());
throw new Exception("file cannot read: " + file.getAbsolutePath());
}
// 文件转byte
is = new FileInputStream(file);
content = GsonUtils.getInputStreamContent(is);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return content;
}
public static void main(String[] args) {
BaiDuVoiceDiscernService service = new BaiDuVoiceDiscernService();
String url = "F:\\demo\\小程序\\2019-10-25\\m4a\\201801021803043151.m4a";
service.token = service.getTocken();
if (StringUtil.isNotEmpty(service.token)) {
service.voiceDiscern(service.token, new File(url));
}
}
}
本文接口交换采用OkHttps 大家可以去之前讲解的springboot项目中copy 或者可以到码云上copy
https://gitee.com/learning_stack_database/springboot
后续持续为大家更新小程序代码 本文如果对您有帮助 请点个关注
(QQ招聘群 710566091
微信招聘群 请加图图微信)