uniapp中实现H5录音和上传、实时语音识别(兼容App小程序)和波形可视化
- Recorder-UniCore插件特性
- 集成到項目中
- 調用錄音
- 上傳錄音
- ASR語音識別
在uniapp中使用Recorder-UniCore插件可以實現跨平臺錄音功能,uniapp自帶的recorderManager接口不支持H5、錄音格式和實時回調onFrameRecorded兼容性不好,用Recorder插件可避免這些問題。
DCloud插件市場下載插件(有demo項目源碼):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等
- 支持實時處理,包括變速變調、實時上傳、ASR語音轉文字
- 支持可視化波形顯示
集成到項目中
1、通過npm安裝recorder-core
//在uniapp項目跟目錄進行npm安裝
npm install recorder-core
2、下載導入Recorder-UniCore插件
// 到插件市場 https://ext.dcloud.net.cn/plugin?name=Recorder-UniCore 下載插件
然后添加到你的項目中 /uni_modules/Recorder-UniCore
3、在vue頁面文件內引入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'
//所有平臺必須引入的uni-app支持文件(如果編譯出現路徑錯誤,請把@換成 ../../ 這種)
import '@/uni_modules/Recorder-UniCore/app-uni-support.js'
/** 需要編譯成微信小程序時,引入微信小程序支持文件 **/
// #ifdef MP-WEIXIN
import 'recorder-core/src/app-support/app-miniProgram-wx-support.js'
// #endif
/** H5、小程序環境中:引入需要的格式編碼器、可視化插件,App環境中在renderjs中引入 **/
// #ifdef H5 || MP-WEIXIN
//按需引入你需要的錄音格式支持文件,如果需要多個格式支持,把這些格式的編碼引擎js文件統統引入進來即可
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine' //如果此格式有額外的編碼引擎(*-engine.js)的話,必須要加上
//可選的插件支持項
import 'recorder-core/src/extensions/waveview'
// #endif
</script>
<!-- #ifdef APP -->
<script module="yourModuleName" lang="renderjs">
/**需要編譯成App時,你需要添加一個renderjs模塊,然后一模一樣的import上面那些js(微信的js除外)
,因為App中默認是在renderjs(WebView)中進行錄音和音頻編碼**/
import 'recorder-core'
import RecordApp from 'recorder-core/src/app-support/app'
import '../../uni_modules/Recorder-UniCore/app-uni-support.js' //renderjs中似乎不支持"@/"打頭的路徑,如果編譯路徑錯誤請改正路徑即可
//按需引入你需要的錄音格式支持文件,和插件
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine'
import 'recorder-core/src/extensions/waveview'
export default {
mounted(){
//App的renderjs必須調用的函數,傳入當前模塊this
RecordApp.UniRenderjsRegister(this);
},
methods: {
//這里定義的方法,在邏輯層中可通過 RecordApp.UniWebViewVueCall(this,'this.xxxFunc()') 直接調用
//調用邏輯層的方法,請直接用 this.$ownerInstance.callMethod("xxxFunc",{args}) 調用,二進制數據需轉成base64來傳遞
}
}
</script>
<!-- #endif -->
調用錄音
/**在邏輯層中編寫**/
//import ... 上面那些import代碼
export default {
data() { return {} }
,mounted() {
this.isMounted=true;
//頁面onShow時【必須調用】的函數,傳入當前組件this
RecordApp.UniPageOnShow(this);
}
,onShow(){ //onShow可能比mounted先執行,頁面可能還未準備好
if(this.isMounted) RecordApp.UniPageOnShow(this);
}
,methods:{
//請求錄音權限
recReq(){
//編譯成App時提供的授權許可(編譯成H5、小程序為免費授權可不填寫);如果未填寫授權許可,將會在App打開后第一次調用請求錄音權限時,彈出“未獲得商用授權時,App上僅供測試”提示框
//RecordApp.UniAppUseLicense='我已獲得UniAppID=*****的商用授權';
RecordApp.UniWebViewActivate(this); //App環境下必須先切換成當前頁面WebView
RecordApp.RequestPermission(()=>{
console.log("已獲得錄音權限,可以開始錄音了");
},(msg,isUserNotAllow)=>{
if(isUserNotAllow){//用戶拒絕了錄音權限
//這里你應當編寫代碼進行引導用戶給錄音權限,不同平臺分別進行編寫
}
console.error("請求錄音權限失敗:"+msg);
});
}
//開始錄音
,recStart(){
//錄音配置信息
var set={
type:"mp3",sampleRate:16000,bitRate:16 //mp3格式,指定采樣率hz、比特率kbps,其他參數使用默認配置;注意:是數字的參數必須提供數字,不要用字符串;需要使用的type類型,需提前把格式支持文件加載進來,比如使用wav格式需要提前加載wav.js編碼引擎
,onProcess:(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd)=>{
//全平臺通用:可實時上傳(發送)數據,配合Recorder.SampleData方法,將buffers中的新數據連續的轉換成pcm上傳,或使用mock方法將新數據連續的轉碼成其他格式上傳,可以參考Recorder文檔里面的:Demo片段列表 -> 實時轉碼并上傳-通用版;基于本功能可以做到:實時轉發數據、實時保存數據、實時語音識別(ASR)等
//注意:App里面是在renderjs中進行實際的音頻格式編碼操作,此處的buffers數據是renderjs實時轉發過來的,修改此處的buffers數據不會改變renderjs中buffers,所以不會改變生成的音頻文件,可在onProcess_renderjs中進行修改操作就沒有此問題了;如需清理buffers內存,此處和onProcess_renderjs中均需要進行清理,H5、小程序中無此限制
//注意:如果你要用只支持在瀏覽器中使用的Recorder擴展插件,App里面請在renderjs中引入此擴展插件,然后在onProcess_renderjs中調用這個插件;H5可直接在這里進行調用,小程序不支持這類插件;如果調用插件的邏輯比較復雜,建議封裝成js文件,這樣邏輯層、renderjs中直接import,不需要重復編寫
//H5、小程序等可視化圖形繪制,直接運行在邏輯層;App里面需要在onProcess_renderjs中進行這些操作
// #ifdef H5 || MP-WEIXIN
if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
// #endif
}
,onProcess_renderjs:`function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){
//App中在這里修改buffers才會改變生成的音頻文件
//App中是在renderjs中進行的可視化圖形繪制,因此需要寫在這里,this是renderjs模塊的this(也可以用This變量);如果代碼比較復雜,請直接在renderjs的methods里面放個方法xxxFunc,這里直接使用this.xxxFunc(args)進行調用
if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
}`
,takeoffEncodeChunk:true?null:(chunkBytes)=>{
//全平臺通用:實時接收到編碼器編碼出來的音頻片段數據,chunkBytes是Uint8Array二進制數據,可以實時上傳(發送)出去
//App中如果未配置RecordApp.UniWithoutAppRenderjs時,建議提供此回調,因為錄音結束后會將整個錄音文件從renderjs傳回邏輯層,由于uni-app的邏輯層和renderjs層數據交互性能實在太拉跨了,大點的文件傳輸會比較慢,提供此回調后可避免Stop時產生超大數據回傳
}
,takeoffEncodeChunk_renderjs:true?null:`function(chunkBytes){
//App中這里可以做一些僅在renderjs中才生效的事情,不提供也行,this是renderjs模塊的this(也可以用This變量)
}`
,start_renderjs:`function(){
//App中可以放一個函數,在Start成功時renderjs中會先調用這里的代碼,this是renderjs模塊的this(也可以用This變量)
//放一些僅在renderjs中才生效的事情,比如初始化,不提供也行
}`
,stop_renderjs:`function(arrayBuffer,duration,mime){
//App中可以放一個函數,在Stop成功時renderjs中會先調用這里的代碼,this是renderjs模塊的this(也可以用This變量)
//放一些僅在renderjs中才生效的事情,不提供也行
}`
};
RecordApp.UniWebViewActivate(this); //App環境下必須先切換成當前頁面WebView
RecordApp.Start(set,()=>{
console.log("已開始錄音");
//創建音頻可視化圖形繪制,App環境下是在renderjs中繪制,H5、小程序等是在邏輯層中繪制,因此需要提供兩段相同的代碼
//view里面放一個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("已暫停");
}
}
//繼續錄音
,recResume(){
if(RecordApp.GetCurrentRecOrNull()){
RecordApp.Resume();
console.log("繼續錄音中...");
}
}
//停止錄音
,recStop(){
RecordApp.Stop((arrayBuffer,duration,mime)=>{
//全平臺通用:arrayBuffer是音頻文件二進制數據,可以保存成文件或者發送給服務器
//App中如果在Start參數中提供了stop_renderjs,renderjs中的函數會比這個函數先執行
//注意:當Start時提供了takeoffEncodeChunk后,你需要自行實時保存錄音文件數據,因此Stop時返回的arrayBuffer的長度將為0字節
//如果當前環境支持Blob,也可以直接構造成Blob文件對象,和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("結束錄音失敗:"+msg);
});
}
}
}
上面代碼中包含了開始錄音、結束錄音、暫停、繼續的功能方法代碼,在view中放幾個按鈕進行點擊調用即可;在onProcess回調中可以做到錄音數據實時處理,可視化圖形的繪制操作也是在onProcess中進行的(Recorder提供了多中可視化波形顯示),H5、App、小程序均可使用。
要編譯成App時,記得先在 manifest.json 中配置好Android和iOS的錄音權限聲明:
//Android需要勾選的權限,第二個必須勾選,不然使用H5錄音時將沒法打開麥克風
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
//iOS需要聲明的權限
NSMicrophoneUsageDescription
上傳錄音
在上面錄音recStop代碼中,結束錄音后會得到ArrayBuffer二進制數據,將ArrayBuffer上傳到服務器即可;實時處理中也支持上傳,實時得到音頻數據的ArrayBuffer后按下面的上傳方法上傳即可。
上傳方式一(簡單):轉成Base64文本上傳
//由于是base64文本,因此直接使用普通的接口請求就可以了,代碼簡單,H5、App、小程序通用
uni.request({
url: "上傳接口地址"
,method: "POST"
,header: { "content-type":"application/x-www-form-urlencoded" }
,data: {
audio: uni.arrayBufferToBase64(arrayBuffer)
,... 其他表單參數 ...
}
,success: (res) => { }
,fail: (err)=>{ }
});
上傳方式二(復雜):使用上傳表單上傳 multipart/form-data
//使用multipart/form-data表單上傳文件,在uniapp中支持不是很好,每個平臺單獨處理
// #ifdef H5
//H5中直接使用瀏覽器提供的File接口構造一個文件
uni.uploadFile({
url: "上傳接口地址"
,file: new File([arrayBuffer], "recorder.mp3")
,name: "audio"
,formData: {
... 其他表單參數 ...
}
,success: (res) => { }
,fail: (err)=>{ }
});
// #endif
// #ifdef APP
//App中直接將二進制數據保存到本地文件,然后再上傳
RecordApp.UniSaveLocalFile("recorder.mp3",arrayBuffer,(savePath)=>{
uni.uploadFile({
url: "上傳接口地址"
,filePath: savePath
,name: "audio"
,formData: {
... 其他表單參數 ...
}
,success: (res) => { }
,fail: (err)=>{ }
});
},(err)=>{});
// #endif
// #ifdef MP-WEIXIN
//小程序中需要將二進制數據保存到本地文件,然后再上傳
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: {
... 其他表單參數 ...
}
,success: (res) => { }
,fail: (err)=>{ }
});
}
,fail:(e)=>{ }
});
// #endif
ASR語音識別
假如你的服務器提供了識別接口,可以參考上面的文件上傳,將文件上傳給你的服務器后,服務器將識別結果返回給前端,此方式可以適配:騰訊云、阿里云、訊飛等的一句話語音識別,或自己搭建的語音識別,比較簡單。
實時的語音識別可以參考Recorder-UniCore插件的demo項目,demo源碼里面有個page_asr.vue示例頁面,可以做到邊錄音邊返回識別結果;此demo使用的是阿里云接口,其他語音識別接口同樣的可以在onProcess中進行實時處理即可完成對接,可以參考Recorder H5錄音開源庫 https://github.com/xiangyuecn/Recorder 中的實時上傳處理demo代碼,不難做到邊錄音邊上傳到語音識別,H5、App、小程序中也是通用的。
【完】
總結
以上是生活随笔為你收集整理的uniapp中实现H5录音和上传、实时语音识别(兼容App小程序)和波形可视化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32CubeMX教程11 RTC
- 下一篇: 【scikit-learn基础】--『监