本身动手封装AudioContext,可作播放器还能够解析音频

前言

使用AudioContext有下面几个好处vue

  • 无需额外引入audio标签git

  • 跟随系统的状态,即手机调成震动/静音模式了,这个声音也就不要出了github

  • 能够音频解析,作特效,好比下面,一个是用canvas手写的,一个是echart作的ajax


Media实现对AudioContext的封装,使用以下canvas

使用方法

1. 引入media

<script src="media.js"></script>复制代码

2. 参数

引入后会在window会挂载一个Media,接受两个参数(source, options)

souce:能够传出一个url或者一个ArrayBufferbash

options异步

  • loop:boolean类型,是否循环播放oop

  • volume:0~1,控制音量ui

  • analyser:是否开启音频分析,使用默认设置能够设为true;也能够是一个对象,size用于配置fftSize,默认1024this

let media = new Media(source, {
  loop: true,
  volume: 0.6,
  analyser: {
    size: 512
  }
})复制代码

3. 事件

onload:音频加载完成,逻辑下载此事件中

onended:音频播放完触发

4. 方法

  • getData 获取分析的音频数据,类型Uint8Array,须要开启analyser选项

  • play 播放音频

  • suspend 暂停播放

  • start(offset) 设置音频开始播放的时刻,offset的范围为0~duration

  • setLoop(bool) 设置音频是否循环播放

  • setVolume(val) 设置音频音量,0 ~ 1.0

  • getCurrentTime 获取当前播放的时长

  • setOptions(options) 能够统一设置,如:{ loop: true, volume: 0.5 }

5. 属性

    • duration 获取音频总时长

    • state 获取当前音频的状态,running | suspend

    • volume 获取当前音量

    • loop 获取音频是否循环

踩的坑

下面说一下封装过程遇到的问题和解决办法

1. 获取当前时间

AudioContext实例上是有个currentTime属性,可是这个属性真的很差用,音频加载完成它就开始更新,不受音频开关的控制,更像是一个age属性,

解决办法,声明一个delta用来保存这之间的差值,每次start需更新这个值,获取小心音频时刻时就相减,固然了,最大值不超过duration。

start(offset) {
  this.delta = this.ctx.currentTime - offset
  // ...}
getCurrentTime() {
   return Math.min(this.ctx.currentTime - this.delta, this.duration)
}复制代码

2. 实现滑动条控制音频播放

AudioContext里面有个start(offset)方法可让音频从哪一个时刻后开始播放,可是这个方法只能使用一次,再次调用会报错,所以若是要实现用滑动条控制音频播放,必须处理start(offset)的问题。解决办法:只能从新生成source,在这以前要先调用stop,否则就会多首音频同时播放。

this.source.stop()
initBufferSource(decodedData) {  this.source = this.ctx.createBufferSource()  this.decodedData = decodedData  this.source.buffer = this.decodedData}复制代码

3. onended事件

本来想注册一个onended事件方便作别的操做,可是每次滑动滚动条,都会触发这个事件,而后音频并无播放完啊。找了很久发现是每次执行stop就会调用,所以在从新生成source前要解绑这个事件,而后从新绑定

this.source.onended = null   
this.onended && (this.source.onended = this.onended)复制代码

4. 处理异步是个问题

里面有这样几个异步,若是开始传来的是url,会先调用request,也就是ajax请求音频资源。

还有一个是decodeAudioData,AudioContext把ArrayBuffer解码也是一个异步,好在新的API返回的是一个Promise对象。

问题是只有解码完成才能够操做音频,想了很久不知道怎么解决暂时注册一个onload事件,操做音频请在这个事件里处理,后续可能会改为返回一个Promise对象

大致是这样子的,特别小的细节就不说了,github有个vue的案例,你们能够看一下

代码

github地址

若是您有什么建议、意见能够留言

相关文章
相关标签/搜索