網(wǎng)站開發(fā)項(xiàng)目技能比賽獲獎(jiǎng)報(bào)道千鋒教育培訓(xùn)機(jī)構(gòu)可靠嗎
文章目錄
- Recorder-UniCore插件特性
- 集成到項(xiàng)目中
- 調(diào)用錄音
- 上傳錄音
- ASR語音識(shí)別
在uniapp中使用Recorder-UniCore插件可以實(shí)現(xiàn)跨平臺(tái)錄音功能,uniapp自帶的recorderManager接口不支持H5、錄音格式和實(shí)時(shí)回調(diào)onFrameRecorded兼容性不好,用Recorder插件可避免這些問題。
DCloud插件市場(chǎng)下載插件(有demo項(xiàng)目源碼):https://ext.dcloud.net.cn/plugin?name=Recorder-UniCore
Recorder-UniCore插件特性
- 支持vue2、vue3、nvue
- 支持編譯成:H5、Android App、iOS App、微信小程序
- 支持已有的大部分錄音格式:mp3、wav、pcm、amr、ogg、g711a、g711u等
- 支持實(shí)時(shí)處理,包括變速變調(diào)、實(shí)時(shí)上傳、ASR語音轉(zhuǎn)文字
- 支持可視化波形顯示
集成到項(xiàng)目中
1、通過npm安裝recorder-core
//在uniapp項(xiàng)目跟目錄進(jìn)行npm安裝
npm install recorder-core
2、下載導(dǎo)入Recorder-UniCore
插件
// 到插件市場(chǎng) https://ext.dcloud.net.cn/plugin?name=Recorder-UniCore 下載插件
然后添加到你的項(xiàng)目中 /uni_modules/Recorder-UniCore
3、在vue頁面文件內(nèi)引入js
<script> /**這里是邏輯層**/
//必須引入的Recorder核心(文件路徑是 /src/recorder-core.js 下同)
import Recorder from 'recorder-core' //使用import、require都行//必須引入的RecordApp核心文件(文件路徑是 /src/app-support/app.js)
import RecordApp from 'recorder-core/src/app-support/app'//所有平臺(tái)必須引入的uni-app支持文件(如果編譯出現(xiàn)路徑錯(cuò)誤,請(qǐng)把@換成 ../../ 這種)
import '@/uni_modules/Recorder-UniCore/app-uni-support.js'/** 需要編譯成微信小程序時(shí),引入微信小程序支持文件 **/
// #ifdef MP-WEIXINimport 'recorder-core/src/app-support/app-miniProgram-wx-support.js'
// #endif/** H5、小程序環(huán)境中:引入需要的格式編碼器、可視化插件,App環(huán)境中在renderjs中引入 **/
// #ifdef H5 || MP-WEIXIN//按需引入你需要的錄音格式支持文件,如果需要多個(gè)格式支持,把這些格式的編碼引擎js文件統(tǒng)統(tǒng)引入進(jìn)來即可import 'recorder-core/src/engine/mp3'import 'recorder-core/src/engine/mp3-engine' //如果此格式有額外的編碼引擎(*-engine.js)的話,必須要加上//可選的插件支持項(xiàng)import 'recorder-core/src/extensions/waveview'
// #endif
</script>
<!-- #ifdef APP -->
<script module="yourModuleName" lang="renderjs">
/**需要編譯成App時(shí),你需要添加一個(gè)renderjs模塊,然后一模一樣的import上面那些js(微信的js除外),因?yàn)锳pp中默認(rèn)是在renderjs(WebView)中進(jìn)行錄音和音頻編碼**/
import 'recorder-core'
import RecordApp from 'recorder-core/src/app-support/app'
import '../../uni_modules/Recorder-UniCore/app-uni-support.js' //renderjs中似乎不支持"@/"打頭的路徑,如果編譯路徑錯(cuò)誤請(qǐng)改正路徑即可//按需引入你需要的錄音格式支持文件,和插件
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine' import 'recorder-core/src/extensions/waveview'export default {mounted(){//App的renderjs必須調(diào)用的函數(shù),傳入當(dāng)前模塊thisRecordApp.UniRenderjsRegister(this);},methods: {//這里定義的方法,在邏輯層中可通過 RecordApp.UniWebViewVueCall(this,'this.xxxFunc()') 直接調(diào)用//調(diào)用邏輯層的方法,請(qǐng)直接用 this.$ownerInstance.callMethod("xxxFunc",{args}) 調(diào)用,二進(jìn)制數(shù)據(jù)需轉(zhuǎn)成base64來傳遞}
}
</script>
<!-- #endif -->
調(diào)用錄音
/**在邏輯層中編寫**/
//import ... 上面那些import代碼export default {
data() { return {} },mounted() {this.isMounted=true;//頁面onShow時(shí)【必須調(diào)用】的函數(shù),傳入當(dāng)前組件thisRecordApp.UniPageOnShow(this);
}
,onShow(){ //onShow可能比mounted先執(zhí)行,頁面可能還未準(zhǔn)備好if(this.isMounted) RecordApp.UniPageOnShow(this);
},methods:{//請(qǐng)求錄音權(quán)限recReq(){//編譯成App時(shí)提供的授權(quán)許可(編譯成H5、小程序?yàn)槊赓M(fèi)授權(quán)可不填寫);如果未填寫授權(quán)許可,將會(huì)在App打開后第一次調(diào)用請(qǐng)求錄音權(quán)限時(shí),彈出“未獲得商用授權(quán)時(shí),App上僅供測(cè)試”提示框//RecordApp.UniAppUseLicense='我已獲得UniAppID=*****的商用授權(quán)';RecordApp.UniWebViewActivate(this); //App環(huán)境下必須先切換成當(dāng)前頁面WebViewRecordApp.RequestPermission(()=>{console.log("已獲得錄音權(quán)限,可以開始錄音了");},(msg,isUserNotAllow)=>{if(isUserNotAllow){//用戶拒絕了錄音權(quán)限//這里你應(yīng)當(dāng)編寫代碼進(jìn)行引導(dǎo)用戶給錄音權(quán)限,不同平臺(tái)分別進(jìn)行編寫}console.error("請(qǐng)求錄音權(quán)限失敗:"+msg);});}//開始錄音,recStart(){//錄音配置信息var set={type:"mp3",sampleRate:16000,bitRate:16 //mp3格式,指定采樣率hz、比特率kbps,其他參數(shù)使用默認(rèn)配置;注意:是數(shù)字的參數(shù)必須提供數(shù)字,不要用字符串;需要使用的type類型,需提前把格式支持文件加載進(jìn)來,比如使用wav格式需要提前加載wav.js編碼引擎,onProcess:(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd)=>{//全平臺(tái)通用:可實(shí)時(shí)上傳(發(fā)送)數(shù)據(jù),配合Recorder.SampleData方法,將buffers中的新數(shù)據(jù)連續(xù)的轉(zhuǎn)換成pcm上傳,或使用mock方法將新數(shù)據(jù)連續(xù)的轉(zhuǎn)碼成其他格式上傳,可以參考Recorder文檔里面的:Demo片段列表 -> 實(shí)時(shí)轉(zhuǎn)碼并上傳-通用版;基于本功能可以做到:實(shí)時(shí)轉(zhuǎn)發(fā)數(shù)據(jù)、實(shí)時(shí)保存數(shù)據(jù)、實(shí)時(shí)語音識(shí)別(ASR)等//注意:App里面是在renderjs中進(jìn)行實(shí)際的音頻格式編碼操作,此處的buffers數(shù)據(jù)是renderjs實(shí)時(shí)轉(zhuǎn)發(fā)過來的,修改此處的buffers數(shù)據(jù)不會(huì)改變r(jià)enderjs中buffers,所以不會(huì)改變生成的音頻文件,可在onProcess_renderjs中進(jìn)行修改操作就沒有此問題了;如需清理buffers內(nèi)存,此處和onProcess_renderjs中均需要進(jìn)行清理,H5、小程序中無此限制//注意:如果你要用只支持在瀏覽器中使用的Recorder擴(kuò)展插件,App里面請(qǐng)?jiān)趓enderjs中引入此擴(kuò)展插件,然后在onProcess_renderjs中調(diào)用這個(gè)插件;H5可直接在這里進(jìn)行調(diào)用,小程序不支持這類插件;如果調(diào)用插件的邏輯比較復(fù)雜,建議封裝成js文件,這樣邏輯層、renderjs中直接import,不需要重復(fù)編寫//H5、小程序等可視化圖形繪制,直接運(yùn)行在邏輯層;App里面需要在onProcess_renderjs中進(jìn)行這些操作// #ifdef H5 || MP-WEIXINif(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);// #endif},onProcess_renderjs:`function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){//App中在這里修改buffers才會(huì)改變生成的音頻文件//App中是在renderjs中進(jìn)行的可視化圖形繪制,因此需要寫在這里,this是renderjs模塊的this(也可以用This變量);如果代碼比較復(fù)雜,請(qǐng)直接在renderjs的methods里面放個(gè)方法xxxFunc,這里直接使用this.xxxFunc(args)進(jìn)行調(diào)用if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);}`,takeoffEncodeChunk:true?null:(chunkBytes)=>{//全平臺(tái)通用:實(shí)時(shí)接收到編碼器編碼出來的音頻片段數(shù)據(jù),chunkBytes是Uint8Array二進(jìn)制數(shù)據(jù),可以實(shí)時(shí)上傳(發(fā)送)出去//App中如果未配置RecordApp.UniWithoutAppRenderjs時(shí),建議提供此回調(diào),因?yàn)殇浺艚Y(jié)束后會(huì)將整個(gè)錄音文件從renderjs傳回邏輯層,由于uni-app的邏輯層和renderjs層數(shù)據(jù)交互性能實(shí)在太拉跨了,大點(diǎn)的文件傳輸會(huì)比較慢,提供此回調(diào)后可避免Stop時(shí)產(chǎn)生超大數(shù)據(jù)回傳},takeoffEncodeChunk_renderjs:true?null:`function(chunkBytes){//App中這里可以做一些僅在renderjs中才生效的事情,不提供也行,this是renderjs模塊的this(也可以用This變量)}`,start_renderjs:`function(){//App中可以放一個(gè)函數(shù),在Start成功時(shí)renderjs中會(huì)先調(diào)用這里的代碼,this是renderjs模塊的this(也可以用This變量)//放一些僅在renderjs中才生效的事情,比如初始化,不提供也行}`,stop_renderjs:`function(arrayBuffer,duration,mime){//App中可以放一個(gè)函數(shù),在Stop成功時(shí)renderjs中會(huì)先調(diào)用這里的代碼,this是renderjs模塊的this(也可以用This變量)//放一些僅在renderjs中才生效的事情,不提供也行}`};RecordApp.UniWebViewActivate(this); //App環(huán)境下必須先切換成當(dāng)前頁面WebViewRecordApp.Start(set,()=>{console.log("已開始錄音");//創(chuàng)建音頻可視化圖形繪制,App環(huán)境下是在renderjs中繪制,H5、小程序等是在邏輯層中繪制,因此需要提供兩段相同的代碼//view里面放一個(gè)canvas,canvas需要指定寬高(下面style里指定了300*100)//<canvas type="2d" class="recwave-WaveView" style="width:300px;height:100px"></canvas>RecordApp.UniFindCanvas(this,[".recwave-WaveView"],`this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});`,(canvas1)=>{this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});});},(msg)=>{console.error("開始錄音失敗:"+msg);});}//暫停錄音,recPause(){if(RecordApp.GetCurrentRecOrNull()){RecordApp.Pause();console.log("已暫停");}}//繼續(xù)錄音,recResume(){if(RecordApp.GetCurrentRecOrNull()){RecordApp.Resume();console.log("繼續(xù)錄音中...");}}//停止錄音,recStop(){RecordApp.Stop((arrayBuffer,duration,mime)=>{//全平臺(tái)通用:arrayBuffer是音頻文件二進(jìn)制數(shù)據(jù),可以保存成文件或者發(fā)送給服務(wù)器//App中如果在Start參數(shù)中提供了stop_renderjs,renderjs中的函數(shù)會(huì)比這個(gè)函數(shù)先執(zhí)行//注意:當(dāng)Start時(shí)提供了takeoffEncodeChunk后,你需要自行實(shí)時(shí)保存錄音文件數(shù)據(jù),因此Stop時(shí)返回的arrayBuffer的長(zhǎng)度將為0字節(jié)//如果當(dāng)前環(huán)境支持Blob,也可以直接構(gòu)造成Blob文件對(duì)象,和Recorder使用一致if(typeof(Blob)!="undefined" && typeof(window)=="object"){var blob=new Blob([arrayBuffer],{type:mime});console.log(blob, (window.URL||webkitURL).createObjectURL(blob));}},(msg)=>{console.error("結(jié)束錄音失敗:"+msg);});}}
}
上面代碼中包含了開始錄音、結(jié)束錄音、暫停、繼續(xù)的功能方法代碼,在view中放幾個(gè)按鈕進(jìn)行點(diǎn)擊調(diào)用即可;在onProcess
回調(diào)中可以做到錄音數(shù)據(jù)實(shí)時(shí)處理,可視化圖形的繪制操作也是在onProcess
中進(jìn)行的(Recorder提供了多中可視化波形顯示),H5、App、小程序均可使用。
要編譯成App時(shí),記得先在 manifest.json
中配置好Android和iOS的錄音權(quán)限聲明:
//Android需要勾選的權(quán)限,第二個(gè)必須勾選,不然使用H5錄音時(shí)將沒法打開麥克風(fēng)
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>//iOS需要聲明的權(quán)限
NSMicrophoneUsageDescription
上傳錄音
在上面錄音recStop代碼中,結(jié)束錄音后會(huì)得到ArrayBuffer二進(jìn)制數(shù)據(jù),將ArrayBuffer上傳到服務(wù)器即可;實(shí)時(shí)處理中也支持上傳,實(shí)時(shí)得到音頻數(shù)據(jù)的ArrayBuffer后按下面的上傳方法上傳即可。
上傳方式一(簡(jiǎn)單):轉(zhuǎn)成Base64文本上傳
//由于是base64文本,因此直接使用普通的接口請(qǐng)求就可以了,代碼簡(jiǎn)單,H5、App、小程序通用uni.request({url: "上傳接口地址",method: "POST",header: { "content-type":"application/x-www-form-urlencoded" },data: {audio: uni.arrayBufferToBase64(arrayBuffer),... 其他表單參數(shù) ...},success: (res) => { },fail: (err)=>{ }
});
上傳方式二(復(fù)雜):使用上傳表單上傳 multipart/form-data
//使用multipart/form-data表單上傳文件,在uniapp中支持不是很好,每個(gè)平臺(tái)單獨(dú)處理// #ifdef H5//H5中直接使用瀏覽器提供的File接口構(gòu)造一個(gè)文件uni.uploadFile({url: "上傳接口地址",file: new File([arrayBuffer], "recorder.mp3"),name: "audio",formData: {... 其他表單參數(shù) ...},success: (res) => { },fail: (err)=>{ }});
// #endif// #ifdef APP//App中直接將二進(jìn)制數(shù)據(jù)保存到本地文件,然后再上傳RecordApp.UniSaveLocalFile("recorder.mp3",arrayBuffer,(savePath)=>{uni.uploadFile({url: "上傳接口地址",filePath: savePath,name: "audio",formData: {... 其他表單參數(shù) ...},success: (res) => { },fail: (err)=>{ }});},(err)=>{});
// #endif// #ifdef MP-WEIXIN//小程序中需要將二進(jìn)制數(shù)據(jù)保存到本地文件,然后再上傳var savePath=wx.env.USER_DATA_PATH+"/recorder.mp3";wx.getFileSystemManager().writeFile({filePath:savePath,data:arrayBuffer,encoding:"binary",success:()=>{wx.uploadFile({url: "上傳接口地址",filePath: savePath,name: "audio",formData: {... 其他表單參數(shù) ...},success: (res) => { },fail: (err)=>{ }});},fail:(e)=>{ }});
// #endif
ASR語音識(shí)別
假如你的服務(wù)器提供了識(shí)別接口,可以參考上面的文件上傳,將文件上傳給你的服務(wù)器后,服務(wù)器將識(shí)別結(jié)果返回給前端,此方式可以適配:騰訊云、阿里云、訊飛等的一句話語音識(shí)別,或自己搭建的語音識(shí)別,比較簡(jiǎn)單。
實(shí)時(shí)的語音識(shí)別可以參考Recorder-UniCore插件的demo項(xiàng)目,demo源碼里面有個(gè)page_asr.vue
示例頁面,可以做到邊錄音邊返回識(shí)別結(jié)果;此demo使用的是阿里云接口,其他語音識(shí)別接口同樣的可以在onProcess
中進(jìn)行實(shí)時(shí)處理即可完成對(duì)接,可以參考Recorder H5錄音開源庫(kù) https://github.com/xiangyuecn/Recorder 中的實(shí)時(shí)上傳處理demo代碼,不難做到邊錄音邊上傳到語音識(shí)別,H5、App、小程序中也是通用的。
【完】