详解HTML5 音频的踩坑之旅

日期:2020-09-16 类型:科技新闻 

关键词:html网页制作,php网页制作,网页设计稿,网页编辑工具,学生网页设计模板

开篇闲扯

前1段時间的1个案件是开发设计1个有声课件,大概便是根据导入文本文档、照片等資源后,网页页面变成相近 PPT 的合理布局,随后选定1张照片,能够插进声频,有单页编写和全局性编写两种方式。在其中声频的导入方法有两种,1种是从資源库中导入,也有1种便是要提到的音频。

说真话,1刚开始都没触碰过 HTML5 的 Audio API,并且要根据在大家接手前的编码中开展提升。自然在其中也踩了很多坑,这次也会紧紧围绕这几个坑来讲说体会(会省略1些基础目标的原始化和获得,由于这些內容并不是这次的关键,有兴趣爱好的同学能够自主搜索 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;
 }
);

1切圆满的话,大家便可以进到下1步了。

(这里有对获得左右文的方式开展了省略,由于这并不是这次的关键)

刚开始音频、中止音频

这里有个较为非常的点,便是必须加上1个正中间自变量来标志是不是当今是不是在音频。由于在火狐访问器上,大家发现1个难题,音频的步骤全是一切正常的,可是点一下中止时却发现如何也中止不上,大家那时候是应用 disconnect 方式。这类方法是不好的,这类方式是必须断掉全部的联接才能够。后来发现,应当提升1个正中间自变量 this.isRecording 来分辨当今是不是正在音频,当点一下刚开始时,将其设定为 true ,中止时将其设定为 false 。

当大家刚开始音频时,会有1个音频监视的恶性事件 onaudioprocess ,假如回到 true 则会将流写入,假如回到 false 则不容易将其写入。因而分辨 this.isRecording ,假如为 false 则立即 return

// 1些原始化
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)); // 获得当今频道的数据信息,并写入数字能量数组
};

自然这里也会有个坑,便是没法再应用,自带获得当今音频时长的方式了,由于具体上其实不是真实的中止,而是沒有将流写入而已。因而大家还必须获得1下当今音频的时长,必须根据1个公式开展获得

const getDuration = () => {
    return (4096 * this.buffers.length) / this.audioContext.sampleRate // 4096为1个流的长度,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;
};

实际能够参照 https://developer.mozilla.org/zh-CN/docs/Web/API/AnalyserNode/frequencyBinCount

其它

  1. HTTPS:在 chrome 下必须全站有 HTTPS 才容许应用
  2. 手机微信:在手机微信内嵌的访问器必须启用 JSSDK 才可以应用
  3. 声频文件格式变换:声频文件格式的方法也是有许多了,能查到的绝大多数材料,大伙儿基础上是相互之间 copy,自然也有1个声频品质的难题,这里就不赘述了。

结语

这次遇到的绝大多数难题全是适配性的难题,因而在上面踩了很多坑,特别是挪动端难题,1刚开始也有出現由于获得音频时长写法不正确的难题,致使立即卡死的状况。这次的亲身经历也填补了 HTML5 API 上的1些空白,自然最关键的還是要提示1下大伙儿,这类原生态的 API 文本文档還是立即查询 MDN 来的简易粗鲁!

以上便是本文的所有內容,期待对大伙儿的学习培训有一定的协助,也期待大伙儿多多适用脚本制作之家。