1.现在很多场景下我们需要直接调用js来创建播放器,这个时候就会遇到一些兼容性问题。在edge、火狐等浏览器中直接用new window.Audio()会播放不了,所以针对edge、火狐等浏览器就可以使用AudioContext来创建播放器。
2.封装一个简单的AudioContext播放器
export class Audio {
_buffers = []
_context
_gainNode
_sourceNode
_url
_state
start = async () => {
try {
await this._getAllBuffer()
this._createAudioEdge().then(() => {
console.log('获取了audio')
}).catch(e => console.log('audio', e))
} catch (e) {
console.log('start Exception', e)
}
}
_createAudioEdge = async () => {
this._context = new AudioContext()
const audioBuffer = await this._decodeAudioData(this._getMergeBuffer())
let { source, gainNode } = this._createSourceNode(audioBuffer)
this._sourceNode = source
this._gainNode = gainNode
}
// 将回调函数转化为promise
_decodeAudioData (arrayBuffer) {
return new Promise((resolve, reject) => {
this._context.decodeAudioData(arrayBuffer, audioData => {
resolve(audioData)
})
})
}
// 得到合并后的buffer
_getMergeBuffer () {
let mergeBuffer
for (let i = 0; i < this._buffers.length; i++) {
let tempBuffer = this._buffers[i]
if (mergeBuffer) { mergeBuffer = this._concatBuffer(mergeBuffer, tempBuffer) } else { mergeBuffer = tempBuffer }
}
return mergeBuffer
}
// 连接两个buffer
_concatBuffer = (buffer1, buffer2) => {
let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength)
let buff1 = new Uint8Array(buffer1)
let buff2 = new Uint8Array(buffer2)
tmp.set(buff1, 0)
tmp.set(buff2, buffer1.byteLength)
return tmp.buffer
}
// 自己获取所有buff,根据自己的场景来获取自己的buff
_getAllBuffer = async () => {
return new Promise((resolve, reject) => {
getAllBuffer(this._url).then(async res => {
this._buffers = []
this._buffers.push(res)
resolve()
}).catch(e => reject(e))
})
}
}
3.创建歌曲的状态值
// Audio的状态
export const AudioState = {
suspended: 'suspended',
running: 'running',
closed: 'closed',
loading: 'loading',
error: 'error'
}
4.播放器的一些操作
/**
* public method
* 播放器逻辑方法
* @returns {Promise<void>}
*/
play = () => {
this.setAudioState(AudioState.running)
this._nativeAudio.play()
}
/**
* public method
* 继续播放
*/
resume () {
this.setAudioState(AudioState.running)
if (this._context) {
this._context.resume()
}
}
/**
* public method
* 暂停播放
*/
pause () {
this.setAudioState(AudioState.suspended)
if (this._context) {
this._context.suspend()
}
}
/**
* public method
* 关闭
*/
close () {
if (!this._context) return
this.setAudioState(AudioState.closed)
this.pause()
this._context.close()
this._context = null
}
/**
* public method
* 歌曲状态设置
*/
setAudioState (val) {
let playStatus = -1 // -1未定义audio,0暂停,1播放,2缓冲, 3播放完毕
switch (val) {
case AudioState.suspended:
playStatus = 0
break
case AudioState.running:
playStatus = 1
break
case AudioState.loading:
playStatus = 2
break
case AudioState.closed:
playStatus = 3
break
case AudioState.error:
playStatus = 4
break
default:
playStatus = -1
break
}
this._state = playStatus
}
get status () {
return this._state
}
一个简单的AudioContext播放器的封装,希望能帮助到大家,如有优化或者问题可以私聊我下。谢谢。