小程序錄音功能實(shí)現(xiàn)
前言
在開(kāi)發(fā)小程序過(guò)程中,有一個(gè)實(shí)現(xiàn)錄音功能并播放錄音,將錄音上傳至服務(wù)器的需求。開(kāi)發(fā)過(guò)程中使用了Taro框架,錄音功能通過(guò)Taro.getRecorderManager()接口實(shí)現(xiàn),上傳錄音至服務(wù)器通過(guò)Taro.uploadFile接口實(shí)現(xiàn),播放錄音使用Taro.createInnerAudioContext()接口實(shí)現(xiàn)。下面就詳細(xì)介紹整個(gè)流程是如何實(shí)現(xiàn)的。
小程序錄音
首先獲取錄音管理器模塊:
const recorderManager = Taro.getRecorderManager();
在組件掛載完畢時(shí)注冊(cè)錄音監(jiān)聽(tīng)事件:
useEffect(() => { // 監(jiān)聽(tīng)錄音開(kāi)始 recorderManager.onStart(() => { console.log('開(kāi)始錄音'); }); // 監(jiān)聽(tīng)錄音暫停 recorderManager.onPause(() => { console.log('暫停錄音'); }); // 監(jiān)聽(tīng)錄音繼續(xù) recorderManager.onResume(() => { console.log('繼續(xù)錄音'); }); // 監(jiān)聽(tīng)錄音停止 recorderManager.onStop((res) => { if (res.duration < 1000) { Taro.showToast({ title: '錄音時(shí)間太短', duration: 1000, icon: 'none', }); } else { console.log('停止錄音'); fileUpload(res.tempFilePath); } }); recorderManager.onError(() => { Taro.showToast({ title: '錄音失??!', duration: 1000, icon: 'none', }); }); }, []);
在錄音onStop的回調(diào)函數(shù)中,我們可以獲取到錄音的臨時(shí)地址res.tempFilePath,但這個(gè)地址是有有效期限的,所以我們需要將這個(gè)錄音上傳至服務(wù)器后臺(tái),進(jìn)行保存,后續(xù)才能正常使用。
onStop回調(diào)函數(shù)中我們調(diào)用了fileUpload函數(shù)實(shí)現(xiàn)文件上傳,fileUpload函數(shù)的實(shí)現(xiàn)如下:
const fileUpload = (tempFilePath) => { Taro.uploadFile({ url: 'http://127.0.0.1:7001/record', // 服務(wù)器地址 filePath: tempFilePath, name: 'file', // 這個(gè)隨便填 header: { 'content-type': 'multipart/form-data', // 格式必須是這個(gè) Authorization: Taro.getStorageSync('token'), }, // formData用于傳輸除文件以外的一些信息 formData: { record_name: '朗誦作品', poem_id: poemInfo.id, category: poemInfo.category, }, success: (res) => { console.log(res); const url = res.data; playAudio(url); // 播放錄音 }, fail: (error) => { console.log('failed!'); console.error(error); }, }); };
需要注意的點(diǎn)是:header中的content-type必須是multipart/form-data。
錄音事件的處理
第一次點(diǎn)擊handleClick就會(huì)觸發(fā)開(kāi)始錄音,之后會(huì)通過(guò)當(dāng)前狀態(tài)判斷是暫停錄音還是繼續(xù)錄音。handleComplete用于停止錄音。
const handleClick = () => { const curPause = pause; setPause(!curPause); if (firstRecord) { setfirstRecord(false); recorderManager.start({ duration: 60000, sampleRate: 44100, numberOfChannels: 1, encodeBitRate: 192000, format: 'mp3', frameSize: 50, }); Taro.showToast({ title: '開(kāi)始錄音', duration: 1000, icon: 'none', }); } else { if (curPause) { recorderManager.pause(); // 暫停錄音 } else { recorderManager.resume(); // 繼續(xù)錄音 } } }; const handleComplete = () => { recorderManager.stop(); // 停止錄音 };
后臺(tái)實(shí)現(xiàn)錄音存儲(chǔ)并返回錄音地址
網(wǎng)上大多數(shù)博客都沒(méi)有涉及這塊內(nèi)容,下面就介紹一下如何實(shí)現(xiàn),后臺(tái)框架我用的是阿里的egg.js。
文件上傳需要配置的東西可見(jiàn)官方文檔:egg.js文件上傳。我們這里使用它的第一種File模式來(lái)實(shí)現(xiàn)。
因?yàn)閑gg.js框架內(nèi)置了Multipart插件,可以解析上傳的multipart/form-data類(lèi)型的數(shù)據(jù)。
首先,現(xiàn)在配置文件config.default.js中寫(xiě)入multipart配置:
module.exports = (app) => { const config = (exports = {}); ... config.multipart = { mode: 'file', fileSize: '50mb', } ... return { ...config, ...userConfig, }; };
然后,在router.js中定義路由:
// 提交錄音 router.post('/record', auth, controller.record.postRecord); 在controller目錄下定義record.js文件寫(xiě)入如下內(nèi)容: const Controller = require('egg').Controller; class RecordController extends Controller { async postRecord() { const { ctx } = this; const file = ctx.request.files[0]; const { record_name, poem_id, category } = ctx.request.body; const res = await ctx.service.record.postRecord(file, record_name, poem_id, category); ctx.body = res; } } module.exports = RecordController;
在service目錄下定義record.js寫(xiě)入具體實(shí)現(xiàn):
const Service = require('egg').Service; let OSS = require('ali-oss'); let aliInfo = { // https://help.aliyun.com/document_detail/31837.html region: 'oss-cn-guangzhou', bucket: 'poem-mini-program', accessKeyId: 'xxx', // 填入阿里云的accessKeyId accessKeySecret: 'xxx', // 填入阿里云的accessKeySecret }; let client = new OSS(aliInfo); class RecordService extends Service { async postRecord(file, record_name, poem_id, category) { const url = await this.uploadOSS(file); await this.updateRecord(url, record_name, poem_id, category); return url; } async uploadOSS(file) { const { ctx } = this; let result; try { // 處理文件,比如上傳到云端 result = await client.put(file.filename, file.filepath); } finally { // 需要?jiǎng)h除臨時(shí)文件 await ctx.cleanupRequestFiles(); } return result.url; } async updateRecord(url, record_name, poem_id, category) { const { ctx } = this; console.log('從ctx.locals中取openid'); console.log(ctx.locals.openid); const openid = ctx.locals.openid; // 將用戶信息記錄到數(shù)據(jù)庫(kù)中 const res = await ctx.model.Record.create({ record_name: record_name, record_url: url, poem_id: poem_id, category: category, openid: openid, }); } } module.exports = RecordService;
這里需要注意的是:
- 需要注冊(cè)阿里云賬號(hào),并在對(duì)象存儲(chǔ)那里新建一個(gè)存儲(chǔ)桶用于存放音頻,也就是云存儲(chǔ)的實(shí)現(xiàn)。
- 需要安裝ali-ossnpm包,用于連接阿里云對(duì)象存儲(chǔ)。在后臺(tái)接收到前端上傳的臨時(shí)文件后,就會(huì)將音頻上傳至阿里云對(duì)象存儲(chǔ)中(client.put)。
播放錄音
細(xì)心的小伙伴可以注意到在使用Taro.uploadFile接口上傳錄音后,在success回調(diào)中調(diào)用了playAudio函數(shù)用于播放音頻,接下來(lái)講一下播放音頻是如何實(shí)現(xiàn)的。
首先,使用Taro.createInnerAudioContext獲取audio的上下文對(duì)象:
const innerAudioText = Taro.createInnerAudioContext();
和錄音一樣,在組件掛載完成時(shí),注冊(cè)監(jiān)聽(tīng)事件:
useEffect(() => { innerAudioText.onPlay(() => { console.log('開(kāi)始播放'); }); innerAudioText.onError((e) => { console.log('播放異常'); console.log(e); }); }, []);
在錄音文件上傳成功后,調(diào)用playAudio方法用于播放錄音:
const playAudio = (url) => { innerAudioText.autoplay = true; innerAudioText.src = url; };
在src被賦予值的時(shí)候,錄音就會(huì)開(kāi)始播放。
總結(jié)
到此這篇關(guān)于小程序錄音功能實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)小程序 錄音內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 小程序?qū)崿F(xiàn)錄音功能
- 微信小程序錄音實(shí)現(xiàn)功能并上傳(使用node解析接收)
- 微信小程序?qū)崿F(xiàn)錄音功能
- 小程序?qū)崿F(xiàn)按下錄音松開(kāi)識(shí)別語(yǔ)音
- 小程序采集錄音并上傳到后臺(tái)
- 小程序?qū)崿F(xiàn)錄音上傳功能
- 微信小程序?qū)崿F(xiàn)錄音時(shí)的麥克風(fēng)動(dòng)畫(huà)效果實(shí)例
- 微信小程序錄音與播放錄音功能
- 微信小程序開(kāi)發(fā)之錄音機(jī) 音頻播放 動(dòng)畫(huà)實(shí)例 (真機(jī)可用)
- 微信小程序-圖片、錄音、音頻播放、音樂(lè)播放、視頻、文件代碼實(shí)例
相關(guān)文章
利用JS獲取IE客戶端IP及MAC的實(shí)現(xiàn)好象不可以
利用JS獲取IE客戶端IP及MAC的實(shí)現(xiàn)好象不可以...2007-01-01React+Typescript實(shí)現(xiàn)倒計(jì)時(shí)Hook的方法
本文主要介紹了React+Typescript實(shí)現(xiàn)倒計(jì)時(shí)Hook的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09一次微信小程序內(nèi)地圖的使用實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了關(guān)于一次微信小程序內(nèi)地圖使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用微信小程序具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09js實(shí)現(xiàn)有趣的倒計(jì)時(shí)效果
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)有趣的倒計(jì)時(shí)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01JavaScript 刪除或抽取字符串指定字符的方法(極為常用)
這篇文章主要給大家分享了極為常用的JavaScript 刪除或抽取字符串指定字符的所有方法,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2021-12-12