[关闭]
@skyway 2015-12-01T03:31:07.000000Z 字数 3526 阅读 970

个人语音实现

高校之恋 JS-SDK 七牛

title: 个人语音实现
date: 2015-11-28 16:09:53
categories: "编程"
tags: [语音, 七牛, 微信JS-SDK, 高校之恋]


此处输入图片的描述

自己挖的坑,果然要自己填!

由于之前开启了CRSF,想增强安全性。过了一段时间,自己吧这事给忘了,导致JS的ajax消息无法发送到后台,一直提示400 BAD request。找了好久才发现,详情

但是也找到个可以检测并且建议的办法,ajax提供error反馈错误信息。

  1. $.ajax({
  2. url: "/profile/{{ user_id }}",
  3. type: 'POST',
  4. data: {data: "failed"},
  5. error: function(e) { //增加错误反馈
  6. console.log(e);
  7. }
  8. })
  9. .done(function (data) {
  10. console.log(data);
  11. });

前后端交互

下载语音

获取token和ticket

说明一下:两处需要用到access_token,一是在微信账号绑定的域名下使用JS-SDK上传文件时,通过token来生成ticket来初始化JS-SDK;二是在下载文件时需要认证号产生的token。

本以为JS-SDK的可以使用未认证账号来产生access_token从而产生ticket用于JS端上传数据,从而避免出现提示“XXXX”需要使用录音功能。但是下载时发现,微信会校验mediaId是否来自同一个公众号(不校验才怪勒)。所以上传和下载必须使用同一个已认证微信公众号的APPID和APPSECRET来产生token。

两个不同的服务器都需要token和ticket,为了避免抢走导致一方失效。一个服务器产生token和ticket存于缓存中,每小时更新一次(微信限制每天不超过2000次),并提供其他服务器获取token和ticket的接口。其他服务器需要使用直接通过接口获取即可。

录音时间

录音时间不需要单独存储,直接存储在audio的链接中,通过锚点的方式
http://7xogxw.com1.z0.glb.clouddn.com/2015-11-26 23:11:06.709113#time23
每次读取audio_url,先分割获取录音时间,url和time分别传到前端渲染。

真正的自适应:关于图片,以后可以通过类似的方式,用锚点记录图片的实际长宽,而在前端加载之前,通过url即可获取长宽数据,从而根据设备实际分辨率,折算合适长宽并发起请求,减少大图加载缓慢。同时可以在图片加载之前就可以生成固定比例的图片占位符,避免加载过程中出现页面跳动。

上传语音

上传文件

之前已经实现过七牛图片的上传,但是当初的接口复杂难用(@Lee 佩服),想着要修改之前的上传接口来上传语音文件,我决定还是使用最新qiniu-sdk来上传文件,之前图床是用到过,使用简洁了很多。

但是一个麻烦的问题,新版本的sdk向下兼容性不是很好,如果使用最新的,之前的会报错,具体不知。而要去修改之前的接口和上传部分代码,工作量太大,于是两个版本sdk同时使用,导入新的包为qiniu2,修改所有引用qiniu位置为qiniu2,OK,一切正常。

一般情况,直接获取token上传数据,相当简单。

  1. import qiniu2
  2. from datetime import datetime
  3. import config
  4. from qiniu2 import BucketManager
  5. import base64
  6. def get_token():
  7. q = qiniu.Auth(config.QINIU_ACCESS_KEY, config.QINIU_SECRET_KEY)
  8. token = q.upload_token(config.PIC_BUCKET)
  9. return token
  10. up_token, key = upload.get_token()
  11. ret, info = qiniu2.put_data(up_token, key, resp)
  12. assert ret['key'] == key

格式转换

而微信默认amr格式,html不支持。上传语音需要预处理,需要policy用于存储转换的格式、另存到位置和名称等信息来产生up_token。并且如果policy和put_data中的key相同且bucket相同,即可同名覆盖,减少空间使用。

这一段单独看七牛的文档你是啥也看不到的,只告诉你预处理格式。segmentfault上有七牛程序员入驻,可查到很多东西

  1. def get_token():
  2. q = qiniu2.Auth(config.QN_ACCESS_KEY, config.QN_SECRET_KEY)
  3. # 文件名称
  4. key = str(datetime.now())
  5. # 转换格式
  6. format = "avthumb/ogg"
  7. # 另存到bucket和对应名称key
  8. entry_uri = config.AUDIO_BUCKET + ':' + key
  9. entry_uri = "saveas/"+ base64.urlsafe_b64encode(entry_uri)
  10. # 独立队列audioQueue转换
  11. policy = {
  12. "persistentOps": format + "|" + entry_uri,
  13. "persistentPipeline": "audioQueue"
  14. }
  15. token = q.upload_token(config.AUDIO_BUCKET, policy=policy)
  16. return token, key
  17. up_token, key = upload.get_token()
  18. ret, info = qiniu2.put_data(up_token, key, resp)
  19. assert ret['key'] == key

删除文件

上传新的语音的时候,需要删除原来的语音文件。同样很简单,提供需要删除的问题件的key即可。

  1. def del_file(upkey):
  2. q = qiniu2.Auth(config.QN_ACCESS_KEY, config.QN_SECRET_KEY)
  3. bucket = BucketManager(q)
  4. ret, info = bucket.delete(config.AUDIO_BUCKET, upkey)
  5. return ret, info

语音播放

兼容格式

一开始看html的audio标签的时候,默认ogg和mp3均可。所以默认转换为ogg。最后iOS上不无法播放,于是检查发现iOS压根就不兼容ogg格式,最终转换为mp3格式。

  1. // 检测能否兼容audio
  2. function support_audio(){
  3. return !!document.createElement('audio').canPlayType;
  4. }
  5. // 检测能否兼容ogg
  6. function support_audio_ogg(){
  7. var elem = document.createElement('audio');
  8. return elem.canPlayType('audio/ogg; codecs="vorbis"');
  9. }
  10. // 检测能否兼容mp3
  11. function support_audio_mp3(){
  12. var elem = document.createElement('audio');
  13. return elem.canPlayType('audio/mpeg;');
  14. }
  15. console.log('audio:' + support_audio());
  16. console.log('audio-ogg:'+ support_audio_ogg());
  17. console.log('audio-mp3:'+ support_audio_mp3());

参考:http://www.vnadd.com/25160.htm

【总结】感觉还是晚起比较好,整天都有状态,11点起来,吃了个饭,然后一直写到晚上12点,以上绝大部分都是这期间完成的,中间吃了个晚饭。原因:牛津大学教授:早睡早起是错误观念,其实我就是想给睡懒觉找借口。

原文链接

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注