前段时间公司要求做一个录音功能。没有头绪,到网上查了下,发现微信的api提供的jssdk能满足我的需求,就决定用这个开发了。先后查了不少资料加上自己琢磨和问前辈的经验,花了大概一个多星期总算完成了,这边记录一下过程。
首先贴一篇教程出来,这篇教程前期省了我不少时间。
微信JSSDK中Config配置:http://blog.csdn.net/zhaojiacan/article/details/51025097 这篇讲的很详细,跟着配置是没问题的,
主要注意的有两点,其一是保证你的项目运行环境是你配置的js安全接口域名之下。其二是链接里面出现的util工具类他没有上传,里面
封装的都是些普通的写入写出方法,自己写都可以这不是重点。
jssdk配置成功后,就可以直接引入微信接口了。
wx.ready(function(){
/**
config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,
所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,
则可以直接调用,不需要放在ready函数中。
*/
var localIds
var lysj //录音时间
var lyCss //样式
var lyName //图片名字
var localIdArr //本地ID集合字符串
var serverIdArr //服务端ID集合字符串
//注册微信播放录音结束事件【一定要放在wx.ready函数内】
/* wx.onVoicePlayEnd({
success: function (res) {
}
}); */
//假设全局变量已经在外部定义
//按下开始录音
$('#talk_btn').on('touchstart', function(event){
event.preventDefault();
START = new Date().getTime();
if(localIds != null){
if(localIdArr == null){
localIdArr = localIds
}else{
localIdArr += "," + localIds;
}
}
localIds = null;
recordTimer = setTimeout(function(){
wx.startRecord({
success: function(){
localStorage.rainAllowRecord = 'true';
wx.onVoiceRecordEnd({
// 录音时间超过一分钟没有停止的时候会执行 complete 回调
complete: function (res) {
END = new Date().getTime();
localIds = res.localId;
alert('最多只能录制一分钟');
}
})
},
cancel: function () {
alert('用户拒绝授权录音');
}
});
},300);
});
var yyTotal = 1; //语音数量
//松手结束录音
$('#talk_btn').on('touchend', function(event){
event.preventDefault();
if(localIds != null){
}else{
END = new Date().getTime();
}
if((END - START) < 300){
END = 0;
START = 0;
//小于300ms,不录音
clearTimeout(recordTimer);
alert("录音时间太短,录音不做保存!")
}else{
$("#voiceButton").show();
lysj = (END - START)/1000;
if(lysj <= 10){
lyName = 10;
lyCss = "height: 42px;width: 79px;";
}else if(10 < lysj && lysj <= 20){
lyName = 20;
lyCss = "height: 42px;width: 129px;";
}else if(20 < lysj && lysj <= 30){
lyName = 30;
lyCss = "height: 42px;width: 177px;";
}else if(30 < lysj && lysj <= 40){
lyName = 40;
lyCss = "height: 42px;width: 227px;";
}else if(40 < lysj && lysj <= 50){
lyName = 50;
lyCss = "height: 42px;width: 277px;";
}else if(50 < lysj && lysj <= 60){
lyName = 60;
lyCss = "height: 42px;width: 327px;";
}else{
lyName = 60;
lyCss = "height: 42px;width: 327px;";
lysj = "60.00";
}
lysj = ""+ lysj +"";
lysj = lysj.substr(0,lysj.lastIndexOf("."));
wx.stopRecord({
success: function (res) {
if(localIds != null){
}else{
localIds = res.localId;
}
if(yyTotal == 1){
$("#rwnrVoice").append(""+ lysj +"s
"
+ "
"
+ " ");
yyTotal = 2;
}else{
$("#rwnrVoice").append(""+ lysj +"s
"
+ "
"
+ " ");
yyTotal++;
}
playVoice(localIds);
},
fail: function (res) {
alert(JSON.stringify(res));
},
});
}
});
//播放语音接口
function playVoice(obj){
wx.playVoice({
localId: obj // 需要播放的音频的本地ID,由stopRecord接口获得
});
}
//播放语音接口
$('#_playVoice').on('click',function(){
wx.playVoice({
localId: localIds // 需要播放的音频的本地ID,由stopRecord接口获得
});
})
//暂停播放接口
$('#_pauseVoice').on('click',function(){
wx.pauseVoice({
localId: localIds // 需要播放的音频的本地ID,由stopRecord接口获得
});
})
//停止播放接口
$('#_stopVoice').on('click',function(){
wx.stopVoice({
localId: localIds // 需要播放的音频的本地ID,由stopRecord接口获得
});
})
//上传录音接口
$('#_uploadVoice').on('click',function(){
var result = confirm("确定上传所有录音吗?");
if(result == true){
//只有一段录音直接上传
if((yyTotal - 1) == 1){
uploadVoice(localIds);
}else{//多段录音,遍历数组上传
//删除最后一段录音
if(localIds == null){
}else{
localIdArr += "," + localIds;
}
var strs= new Array();
strs = localIdArr.split(",");
for (i=0;i
这边是我调用到的接口,前端辞职了,我也就知道把样式写上来了,将就看。因为这边考虑到用户会多条语音上传,且不用用户录一条点一次上传这么麻烦,这边就创建几个全局变量,录好的本地id在存在变量里。用户点上传的时候直接全部上传。同时把返回的serverId也是放到一个集合里在表单提交到后台下载到自己服务器上。
接着是后台下载微信临时资源到本地服务器比且转码(我们上传的录音),因为下载的资源是amr格式的,h5不支持播放,我们得转码,为了不浪费服务器的内存,转码后顺便把amr格式的录音删了。
/**
*
* 根据文件id下载文件
*
*
*
* @param mediaId
*
* 媒体id
*
* @throws Exception
*/
public static String getInputStream(String mediaId) {
InputStream is = null;
File amrPath = null;
File mp3Path = null;
String access_token = PropertiesLoader.readProperties("access_token", "wxHelp.properties");
String url = "https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token="
+ access_token + "&media_id=" + mediaId;
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet
.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type","audio/mp3");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
// 获取文件转化为byte流
is = http.getInputStream();
//获取项目路径
String path = Thread.currentThread().getContextClassLoader().getResource("").toString();
path = path.replace('/', '\\'); // 将/换成\
path = path.replace("file:", ""); //去掉file:
path = path.replace("classes\\", ""); //去掉classes\
path = path.replace("target\\", ""); //去掉target\
path = path.replace("WEB-INF\\", "");//去掉web-inf\
path = path.substring(1); //去掉第一个\,如 \D:\JavaWeb...
//文件添加下级目录地址
path += "static"+File.separator +"common" + File.separator +"voice";
UUID uuid = UUID.randomUUID();
String fileName = uuid.toString().replace("-", "");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
File file = new File(path);
File todayFile = new File(path + "\\" + sdf.format(new Date()));
amrPath = new File(todayFile + "\\" + fileName + ".amr");
mp3Path = new File(amrPath.toString().replace(".amr", ".mp3"));
//如果文件夹不存在则创建
if (!file.exists() && !file.isDirectory()){
file.mkdir();
}
if (!todayFile.exists() && !todayFile.isDirectory()){
todayFile.mkdir();
}
BufferedInputStream in = new BufferedInputStream(is);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(amrPath));
byte[] by = new byte[1024];
int lend = 0;
while((lend = in.read(by)) != -1){
out.write(by,0,lend);
}
in.close();
out.close();
//转码
changeToMp3(amrPath.toString(),mp3Path.toString());
//删除amr文件
if(amrPath.isFile() && amrPath.exists()){
amrPath.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
//返回一个数据库存储的格式 :wgBank\static\common\voice\2017-10-23\3d1043b7dafe44a78cf4f2e45047d999.mp3
String newPath = mp3Path.toString().replace("\\", "/");
newPath = newPath.substring(newPath.toString().lastIndexOf("/wgBank"));
return newPath;
}
public static void changeToMp3(String sourcePath, String targetPath) {
File source = new File(sourcePath);
File target = new File(targetPath);
AudioAttributes audio = new AudioAttributes();
Encoder encoder = new Encoder();
audio.setCodec("libmp3lame");
EncodingAttributes attrs = new EncodingAttributes();
attrs.setFormat("mp3");
attrs.setAudioAttributes(audio);
try {
encoder.encode(source, target, attrs);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InputFormatException e) {
e.printStackTrace();
} catch (EncoderException e) {
e.printStackTrace();
}
}
至此,返回的路径就可以存在数据库了,展示的时候直接数据库获取路径,然后h5播放就可以了。
语音详情:
=========================================开发过程中遇到的一些问题和解决方法=============================================================
1:防止长按button时,自动触发系统事件(复制,拷贝,剪切啥的)。给button加个样式:ontouchstart="return false;"
2:连续多次点击播放的时候,会导致微信闪退卡死。所以播放之前最好先初始化一下录音
//播放语音接口 播放的时候先初始化
function playVoice2(obj){
var ua = navigator.userAgent.toLowerCase();
if (/iphone|ipad|ipod/.test(ua)) {
wx.stopVoice({
localId: obj // 需要播放的音频的本地ID,由stopRecord接口获得
});
} else if (/android/.test(ua)) {
wx.stopVoice({
localId: obj // 需要播放的音频的本地ID,由stopRecord接口获得
});
}
wx.playVoice({
localId: obj // 需要播放的音频的本地ID,由stopRecord接口获得
});
}
3:时间过短不录音和超过一分钟停止录音,上面代码已经有解决方法。
4:下载下来的时候,电脑也播放不了。这个问题卡了挺久,后来给前辈看了下我的代码才发现问题。
![]()
一开始写的是"application/x-www-form-urlencoded"的json文本形式,但是我下的是音频,所以一直都是文件损坏,播放不了。
视频:video/mpeg4
音频:audio/mp3
5:最最最乌龙 卡我最最最长时间 也是解决方法中最最最简单的,~~用错api了,我开发的是企业号,但是我用的是服务号的api,之前一直不知道企业号和服务号的api是分开的
服务号api:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
企业号api:http://qydev.weixin.qq.com/wiki/index.php?title=%E9%A6%96%E9%A1%B5
(微信接口开发,测试肯定是要在外网上才能测试,如何本地测试接口呢,就得把本机的ip封装成正规域名,然后修改微信后排的js安全接口。这样就可以测试拉。)
推荐大家用这款工具:natapp,官网有教程~成功的界面大致是这样的,这样可以直接访问域名:h4g4rc.natappfree.cc来访问到本机了。
![]()
你可能感兴趣的:(微信录音,下载,转码,jssdk)