title: 個(gè)人語(yǔ)音實(shí)現(xiàn)
date: 2015-11-28 16:09:53
categories: "編程"
tags: [語(yǔ)音, 七牛, 微信JS-SDK, 高校之戀]
自己挖的坑弛作,果然要自己填蝠咆!
由于之前開啟了CRSF,想增強(qiáng)安全性月幌。過了一段時(shí)間,自己吧這事給忘了萝衩,導(dǎo)致JS的ajax消息無(wú)法發(fā)送到后臺(tái)豆村,一直提示400 BAD request驼鞭。找了好久才發(fā)現(xiàn)庶弃,詳情衫贬。
但是也找到個(gè)可以檢測(cè)并且建議的辦法,ajax提供error反饋錯(cuò)誤信息歇攻。
$.ajax({
url: "/profile/{{ user_id }}",
type: 'POST',
data: {data: "failed"},
error: function(e) { //增加錯(cuò)誤反饋
console.log(e);
}
})
.done(function (data) {
console.log(data);
});
前后端交互
- 訪問個(gè)人主頁(yè)(wx_config)
- 微信上傳語(yǔ)音
- 傳遞mediaId和record_time到后臺(tái)
- 獲取token從微信下載語(yǔ)音
- 上傳語(yǔ)音到qiniu(發(fā)起任務(wù)轉(zhuǎn)換amr為mp3)
- 存儲(chǔ)url+time到數(shù)據(jù)庫(kù)
下載語(yǔ)音
獲取token和ticket
說明一下:兩處需要用到access_token固惯,一是在微信賬號(hào)綁定的域名下使用JS-SDK上傳文件時(shí),通過token來(lái)生成ticket來(lái)初始化JS-SDK掉伏;二是在下載文件時(shí)需要認(rèn)證號(hào)產(chǎn)生的token。
本以為JS-SDK的可以使用未認(rèn)證賬號(hào)來(lái)產(chǎn)生access_token從而產(chǎn)生ticket用于JS端上傳數(shù)據(jù)澳窑,從而避免出現(xiàn)提示“XXXX”需要使用錄音功能斧散。但是下載時(shí)發(fā)現(xiàn),微信會(huì)校驗(yàn)mediaId是否來(lái)自同一個(gè)公眾號(hào)(不校驗(yàn)才怪勒)摊聋。所以上傳和下載必須使用同一個(gè)已認(rèn)證微信公眾號(hào)的APPID和APPSECRET來(lái)產(chǎn)生token鸡捐。
兩個(gè)不同的服務(wù)器都需要token和ticket,為了避免搶走導(dǎo)致一方失效麻裁。一個(gè)服務(wù)器產(chǎn)生token和ticket存于緩存中箍镜,每小時(shí)更新一次(微信限制每天不超過2000次),并提供其他服務(wù)器獲取token和ticket的接口煎源。其他服務(wù)器需要使用直接通過接口獲取即可色迂。
錄音時(shí)間
錄音時(shí)間不需要單獨(dú)存儲(chǔ),直接存儲(chǔ)在audio的鏈接中手销,通過錨點(diǎn)的方式
http://7xogxw.com1.z0.glb.clouddn.com/2015-11-26 23:11:06.709113#time23
每次讀取audio_url歇僧,先分割獲取錄音時(shí)間,url和time分別傳到前端渲染锋拖。
真正的自適應(yīng):關(guān)于圖片诈悍,以后可以通過類似的方式,用錨點(diǎn)記錄圖片的實(shí)際長(zhǎng)寬兽埃,而在前端加載之前侥钳,通過url即可獲取長(zhǎng)寬數(shù)據(jù),從而根據(jù)設(shè)備實(shí)際分辨率柄错,折算合適長(zhǎng)寬并發(fā)起請(qǐng)求舷夺,減少大圖加載緩慢。同時(shí)可以在圖片加載之前就可以生成固定比例的圖片占位符售貌,避免加載過程中出現(xiàn)頁(yè)面跳動(dòng)冕房。
上傳語(yǔ)音
上傳文件
之前已經(jīng)實(shí)現(xiàn)過七牛圖片的上傳,但是當(dāng)初的接口復(fù)雜難用(@Lee 佩服)趁矾,想著要修改之前的上傳接口來(lái)上傳語(yǔ)音文件耙册,我決定還是使用最新qiniu-sdk來(lái)上傳文件,之前圖床是用到過毫捣,使用簡(jiǎn)潔了很多详拙。
但是一個(gè)麻煩的問題帝际,新版本的sdk向下兼容性不是很好,如果使用最新的饶辙,之前的會(huì)報(bào)錯(cuò)蹲诀,具體不知。而要去修改之前的接口和上傳部分代碼弃揽,工作量太大料仗,于是兩個(gè)版本sdk同時(shí)使用,導(dǎo)入新的包為qiniu2粱坤,修改所有引用qiniu
位置為qiniu2
念搬,OK,一切正常涌矢。
一般情況掖举,直接獲取token上傳數(shù)據(jù),相當(dāng)簡(jiǎn)單娜庇。
import qiniu2
from datetime import datetime
import config
from qiniu2 import BucketManager
import base64
def get_token():
q = qiniu.Auth(config.QINIU_ACCESS_KEY, config.QINIU_SECRET_KEY)
token = q.upload_token(config.PIC_BUCKET)
return token
up_token, key = upload.get_token()
ret, info = qiniu2.put_data(up_token, key, resp)
assert ret['key'] == key
格式轉(zhuǎn)換
而微信默認(rèn)amr格式塔次,html不支持。上傳語(yǔ)音需要預(yù)處理名秀,需要policy用于存儲(chǔ)轉(zhuǎn)換的格式励负、另存到位置和名稱等信息來(lái)產(chǎn)生up_token。并且如果policy和put_data中的key相同且bucket相同匕得,即可同名覆蓋熄守,減少空間使用。
這一段單獨(dú)看七牛的文檔你是啥也看不到的耗跛,只告訴你預(yù)處理格式裕照。segmentfault上有七牛程序員入駐,可查到很多東西
def get_token():
q = qiniu2.Auth(config.QN_ACCESS_KEY, config.QN_SECRET_KEY)
# 文件名稱
key = str(datetime.now())
# 轉(zhuǎn)換格式
format = "avthumb/ogg"
# 另存到bucket和對(duì)應(yīng)名稱key
entry_uri = config.AUDIO_BUCKET + ':' + key
entry_uri = "saveas/"+ base64.urlsafe_b64encode(entry_uri)
# 獨(dú)立隊(duì)列audioQueue轉(zhuǎn)換
policy = {
"persistentOps": format + "|" + entry_uri,
"persistentPipeline": "audioQueue"
}
token = q.upload_token(config.AUDIO_BUCKET, policy=policy)
return token, key
up_token, key = upload.get_token()
ret, info = qiniu2.put_data(up_token, key, resp)
assert ret['key'] == key
刪除文件
上傳新的語(yǔ)音的時(shí)候调塌,需要?jiǎng)h除原來(lái)的語(yǔ)音文件晋南。同樣很簡(jiǎn)單,提供需要?jiǎng)h除的問題件的key即可羔砾。
def del_file(upkey):
q = qiniu2.Auth(config.QN_ACCESS_KEY, config.QN_SECRET_KEY)
bucket = BucketManager(q)
ret, info = bucket.delete(config.AUDIO_BUCKET, upkey)
return ret, info
語(yǔ)音播放
兼容格式
一開始看html的audio標(biāo)簽的時(shí)候负间,默認(rèn)ogg和mp3均可。所以默認(rèn)轉(zhuǎn)換為ogg姜凄。最后iOS上不無(wú)法播放政溃,于是檢查發(fā)現(xiàn)iOS壓根就不兼容ogg格式,最終轉(zhuǎn)換為mp3格式态秧。
- iOS錄音PC能播放董虱,不是前端、后臺(tái)原因。
- 確定iOS的微信兼容audio
全民K哥能播放愤诱,全民K哥的js判斷支持h5則使用audio否則flash云头,而微信支持h5。通過canPlayType屬性即可檢測(cè)淫半。 - 測(cè)試audio兼容性(如果最早就加入并進(jìn)行檢測(cè)溃槐,前面的都不用折騰)
// 檢測(cè)能否兼容audio
function support_audio(){
return !!document.createElement('audio').canPlayType;
}
// 檢測(cè)能否兼容ogg
function support_audio_ogg(){
var elem = document.createElement('audio');
return elem.canPlayType('audio/ogg; codecs="vorbis"');
}
// 檢測(cè)能否兼容mp3
function support_audio_mp3(){
var elem = document.createElement('audio');
return elem.canPlayType('audio/mpeg;');
}
console.log('audio:' + support_audio());
console.log('audio-ogg:'+ support_audio_ogg());
console.log('audio-mp3:'+ support_audio_mp3());
參考:http://www.vnadd.com/25160.htm
- 使用jsconsole遠(yuǎn)程調(diào)試
通過該工具可以遠(yuǎn)程查看訪問機(jī)器輸出到console的數(shù)據(jù),即可知道是否兼容科吭。