首頁  >  文章  >  web前端  >  詳解HTML5 錄音遇到的坑

詳解HTML5 錄音遇到的坑

小云云
小云云原創
2018-05-17 14:25:338658瀏覽

本文恩主要介紹了詳解HTML5 錄音的踩坑之旅,小編覺得蠻不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。

說實話,一開始都沒接觸過 HTML5 的 Audio API,而且要基於在我們接手前的程式碼中進行最佳化。當然其中也踩了不少坑,這次也會圍繞這幾個坑來說說感受(會省略一些基本對象的初始化和獲取,因為這些內容不是這次的重點,有興趣的同學可以自行查找MDN上的文件):

  1. 呼叫Audio API 的相容性寫法

  2. 取得錄音聲音的大小(應該是頻率)

  3. 暫停錄音的相容性寫法

  4. 取得目前錄音時間

錄音前的準備

開始錄音前,要先取得目前裝置是否支援Audio API。早期的方法 navigator.getUserMedia 已經被 navigator.mediaDevices.getUserMedia 取代。正常來說現在大部分的現代瀏覽器都已經支援navigator.mediaDevices.getUserMedia 的用法了,當然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;
}

因為這個方法是異步的,所以我們可以對無法相容的裝置進行友善的提示

navigator.mediaDevices.getUserMedia(constraints).then(
 function(mediaStream) {
 // 成功
 },
 function(error) {
 // 失败
 const { name } = error;
 let errorMessage;
 switch (name) {
 // 用户拒绝
 case 'NotAllowedError':
 case 'PermissionDeniedError':
 errorMessage = '用户已禁止网页调用录音设备';
 break;
 // 没接入录音设备
 case 'NotFoundError':
 case 'DevicesNotFoundError':
 errorMessage = '录音设备未找到';
 break;
 // 其它错误
 case 'NotSupportedError':
 errorMessage = '不支持录音功能';
 break;
 default:
 errorMessage = '录音调用错误';
 window.console.log(error);
 }
 return errorMessage;
 }
);

一切順利的話,我們就可以進入下一步了。

(這裡有對獲取上下文的方法進行了省略,因為這不是這次的重點)

#開始錄音、暫停錄音

這裡有個比較特別的點,就是需要加入一個中間變數來標識是否目前是否在錄音。因為在火狐瀏覽器上,我們發現一個問題,錄音的流程都是正常的,但是點擊暫停時卻發現怎麼也暫停不了,我們當時是使用 disconnect 方法。這種方式是不行的,這種方法是需要斷開所有的連接才可以。後來發現,應該增加一個中間變數 this.isRecording 來判斷目前是否正在錄音,當點擊開始時,將其設為 true ,暫停時將其設為 false 。

當我們開始錄音時,會有一個錄音監聽的事件 onaudioprocess ,如果返回 true 則會將流寫入,如果返回 false 則不會將其寫入。因此判斷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);
// 监听录音的过程
scriptNode.onaudioprocess = event => {
 if (!this.isRecording) return; // 判断是否正则录音
 this.buffers.push(event.inputBuffer.getChannelData(0)); // 获取当前频道的数据,并写入数组
};

當然這裡也會有個坑,就是無法再使用,自帶獲取當前錄音時長的方法了,因為實際上並不是真正的暫停,而是沒有將流寫入罷了。於是我們還需要取得目前錄音的時長,需要透過一個公式進行取得

const getDuration = () => {
    return (4096 * this.buffers.length) / this.audioContext.sampleRate // 4096为一个流的长度,sampleRate 为采样率
}

這樣就能夠取得正確的錄音時長了。

結束錄音

結束錄音的方式,我採用的是先暫停,之後需要試聽或者其它的操作先執行,然後再將儲存流的陣列長度置為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;
};

其它

  1. #HTTPS:在chrome 下需要全站有HTTPS 才允許使用

  2. 微信:在微信內建的瀏覽器需要呼叫JSSDK 才能使用

  3. 音訊格式轉換:音訊格式的方式也有很多了,能查到的大部分資料,大家基本上是互相copy,當然還有一個音訊品質的問題,這裡就不贅述了。

結語

這次遇到的大部分問題都是相容性的問題,因此在上面踩了不少坑,尤其是行動端的問題,一開始還有出現因為取得錄音時長寫法錯誤的問題,導致直接卡死的情況。這次的經驗也彌補了 HTML5 API 上的一些空白,當然最重要的還是要提醒一下大家,這種原生的 API 文件還是直接查看 MDN 來的簡單粗暴!

相關推薦:

關於錄音的10篇文章推薦

微信開發之錄音功能

詳解HTML5網頁錄音與壓縮的範例程式碼

#

以上是詳解HTML5 錄音遇到的坑的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn