這篇文章將為大家詳細(xì)講解有關(guān)HTML5中實(shí)現(xiàn)錄音的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
在同安等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站制作、網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需網(wǎng)站建設(shè),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),全網(wǎng)整合營(yíng)銷推廣,外貿(mào)營(yíng)銷網(wǎng)站建設(shè),同安網(wǎng)站建設(shè)費(fèi)用合理。說(shuō)實(shí)話,一開始都沒(méi)接觸過(guò) HTML5 的 Audio API,而且要基于在我們接手前的代碼中進(jìn)行優(yōu)化。當(dāng)然其中也踩了不少坑,這次也會(huì)圍繞這幾個(gè)坑來(lái)說(shuō)說(shuō)感受(會(huì)省略一些基本對(duì)象的初始化和獲取,因?yàn)檫@些內(nèi)容不是這次的重點(diǎn),有興趣的同學(xué)可以自行查找 MDN 上的文檔):
調(diào)用 Audio API 的兼容性寫法
獲取錄音聲音的大?。☉?yīng)該是頻率)
暫停錄音的兼容性寫法
獲取當(dāng)前錄音時(shí)間
錄音前的準(zhǔn)備
開始錄音前,要先獲取當(dāng)前設(shè)備是否支持 Audio API。早期的方法 navigator.getUserMedia 已經(jīng)被 navigator.mediaDevices.getUserMedia 所代替。正常來(lái)說(shuō)現(xiàn)在大部分的現(xiàn)代瀏覽器都已經(jīng)支持 navigator.mediaDevices.getUserMedia 的用法了,當(dāng)然 MDN 上也給出了兼容性的寫法
const promisifiedOldGUM = function(constraints) { // First get ahold of getUserMedia, if present const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; // Some browsers just don't implement it - return a rejected promise with an error // to keep a consistent interface if (!getUserMedia) { return Promise.reject( new Error('getUserMedia is not implemented in this browser') ); } // Otherwise, wrap the call to the old navigator.getUserMedia with a Promise return new Promise(function(resolve, reject) { getUserMedia.call(navigator, constraints, resolve, reject); }); }; // Older browsers might not implement mediaDevices at all, so we set an empty object first if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {}; } // Some browsers partially implement mediaDevices. We can't just assign an object // with getUserMedia as it would overwrite existing properties. // Here, we will just add the getUserMedia property if it's missing. if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = promisifiedOldGUM; }
因?yàn)檫@個(gè)方法是異步的,所以我們可以對(duì)無(wú)法兼容的設(shè)備進(jìn)行友好的提示
navigator.mediaDevices.getUserMedia(constraints).then( function(mediaStream) { // 成功 }, function(error) { // 失敗 const { name } = error; let errorMessage; switch (name) { // 用戶拒絕 case 'NotAllowedError': case 'PermissionDeniedError': errorMessage = '用戶已禁止網(wǎng)頁(yè)調(diào)用錄音設(shè)備'; break; // 沒(méi)接入錄音設(shè)備 case 'NotFoundError': case 'DevicesNotFoundError': errorMessage = '錄音設(shè)備未找到'; break; // 其它錯(cuò)誤 case 'NotSupportedError': errorMessage = '不支持錄音功能'; break; default: errorMessage = '錄音調(diào)用錯(cuò)誤'; window.console.log(error); } return errorMessage; } );
一切順利的話,我們就可以進(jìn)入下一步了。
(這里有對(duì)獲取上下文的方法進(jìn)行了省略,因?yàn)檫@不是這次的重點(diǎn))
開始錄音、暫停錄音
這里有個(gè)比較特別的點(diǎn),就是需要添加一個(gè)中間變量來(lái)標(biāo)識(shí)是否當(dāng)前是否在錄音。因?yàn)樵诨鸷鼮g覽器上,我們發(fā)現(xiàn)一個(gè)問(wèn)題,錄音的流程都是正常的,但是點(diǎn)擊暫停時(shí)卻發(fā)現(xiàn)怎么也暫停不了,我們當(dāng)時(shí)是使用 disconnect 方法。這種方式是不行的,這種方法是需要斷開所有的連接才可以。后來(lái)發(fā)現(xiàn),應(yīng)該增加一個(gè)中間變量 this.isRecording 來(lái)判斷當(dāng)前是否正在錄音,當(dāng)點(diǎn)擊開始時(shí),將其設(shè)置為 true ,暫停時(shí)將其設(shè)置為 false 。
當(dāng)我們開始錄音時(shí),會(huì)有一個(gè)錄音監(jiān)聽的事件 onaudioprocess ,如果返回 true 則會(huì)將流寫入,如果返回 false 則不會(huì)將其寫入。因此判斷 this.isRecording ,如果為 false 則直接 return
// 一些初始化 const audioContext = new AudioContext(); const sourceNode = audioContext.createMediaStreamSource(mediaStream); const scriptNode = audioContext.createScriptProcessor( BUFFER_SIZE, INPUT_CHANNELS_NUM, OUPUT_CHANNELS_NUM ); sourceNode.connect(this.scriptNode); scriptNode.connect(this.audioContext.destination); // 監(jiān)聽錄音的過(guò)程 scriptNode.onaudioprocess = event => { if (!this.isRecording) return; // 判斷是否正則錄音 this.buffers.push(event.inputBuffer.getChannelData(0)); // 獲取當(dāng)前頻道的數(shù)據(jù),并寫入數(shù)組 };
當(dāng)然這里也會(huì)有個(gè)坑,就是無(wú)法再使用,自帶獲取當(dāng)前錄音時(shí)長(zhǎng)的方法了,因?yàn)閷?shí)際上并不是真正的暫停,而是沒(méi)有將流寫入罷了。于是我們還需要獲取一下當(dāng)前錄音的時(shí)長(zhǎng),需要通過(guò)一個(gè)公式進(jìn)行獲取
const getDuration = () => { return (4096 * this.buffers.length) / this.audioContext.sampleRate // 4096為一個(gè)流的長(zhǎng)度,sampleRate 為采樣率 }
這樣就能夠獲取正確的錄音時(shí)長(zhǎng)了。
結(jié)束錄音
結(jié)束錄音的方式,我采用的是先暫停,之后需要試聽或者其它的操作先執(zhí)行,然后再將存儲(chǔ)流的數(shù)組長(zhǎng)度置為 0。
獲取頻率
getVoiceSize = analyser => { const dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray); const data = dataArray.slice(100, 1000); const sum = data.reduce((a, b) => a + b); return sum; };
其它
HTTPS:在 chrome 下需要全站有 HTTPS 才允許使用
微信:在微信內(nèi)置的瀏覽器需要調(diào)用 JSSDK 才能使用
音頻格式轉(zhuǎn)換:音頻格式的方式也有很多了,能查到的大部分資料,大家基本上是互相 copy,當(dāng)然還有一個(gè)音頻質(zhì)量的問(wèn)題,這里就不贅述了。
關(guān)于“HTML5中實(shí)現(xiàn)錄音的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。