import hw from 'howler'
import EventEmitter from 'eventemitter3'
import toString from 'lodash-es/toString.js'
import isNumber from 'lodash-es/isNumber.js'
let Howl = hw.Howl
function fmtTime(t) {
function f2(i) {
if (i < 10) {
return '0' + toString(i)
}
return toString(i)
}
let h = Math.floor(t / 3600)
let m = Math.floor(t % 3600 / 60)
let s = Math.floor(t % 3600 % 60)
let ch = h > 0 ? f2(h) + ':' : ''
let cm = f2(m) + ':'
let cs = f2(s)
return `${ch}${cm}${cs}`
}
/**
* 封裝音頻播放Howler
*
* See: {@link https://github.com/goldfire/howler.js/ Howler.js}
*
* @returns {Object} 回傳事件觸發器物件,包含seek、getSeek、getState、pause、resume、stop、play、end,play輸入為網址與副檔名(預設mp3),包含on與emit事件,on為註冊監聽事件,emit為觸發事件
*/
function WHowler() {
let adp = null
//ev
let ev = new EventEmitter()
function seek(r) {
if (adp === null) {
return
}
try {
let s = getSeek()
adp.seek(r * s.tall)
emitRefresh()
}
catch (e) {}
}
ev.seek = seek
function getSeek() {
let r = null
if (adp === null) {
return r
}
try {
let t = adp.seek()
let tall = adp.duration()
if (isNumber(t) && isNumber(tall)) {
r = {
t,
tall,
r: t / tall,
}
}
}
catch (e) {}
return r
}
ev.getSeek = getSeek
function getState() {
let r = null
if (adp === null) {
return r
}
try {
r = adp.state()
}
catch (e) {}
return r
}
ev.getState = getState
function pause() {
if (adp === null) {
return
}
try {
adp.pause()
}
catch (e) {}
}
ev.pause = pause
function resume() {
if (adp === null) {
return
}
try {
adp.play()
}
catch (e) {}
}
ev.resume = resume
function stopForce(adpTar) {
try {
adpTar.stop()
adpTar.unload()
}
catch (e) {
// console.log('stopForce', e)
}
}
function stopTar(adpTar) {
if (adpTar === null) {
return
}
let t = setInterval(() => { //為loading時可能無法呼叫stop與unload, 故得用timer偵測
stopForce(adpTar)
if (adpTar.state() === 'unloaded') {
adpTar = null
clearInterval(t)
}
}, 1)
}
function stop() {
if (adp === null) {
return
}
stopTar(adp)
}
ev.stop = stop
function play(src, format = 'mp3') {
//src可為url或base64格式(可通過blob2b64取得)
//check
if (adp !== null) {
let adpTar = adp
stopTar(adpTar)
}
//play
try {
adp = new Howl({
src,
format,
})
}
catch (err) {
emitError({ from: 'new Howl', err })
return
}
try {
adp.play()
}
catch (err) {
emitError({ from: 'play', err })
return
}
//refresh
adp.timer = setInterval(() => {
//console.log('timer refresh', adp.timer)
emitRefresh()
}, 50)
//loaderror
adp.on('loaderror', function() {
emitError('loaderror')
stop()
})
//playerror
adp.on('playerror', function() {
emitError('playerror')
stop()
})
//end
adp.on('end', function() {
emitFinish()
stop()
})
}
ev.play = play
function emitFinish() {
setTimeout(function() {
ev.emit('end')
}, 1)
}
function emitError(err) {
setTimeout(function() {
ev.emit('error', { err })
}, 1)
}
function emitRefresh() {
setTimeout(function() {
let s = getSeek()
if (s !== null) {
let prog = s.r * 100
let timeNow = fmtTime(s.t)
let timeEnd = fmtTime(s.tall)
let timeShow = `${timeNow}/${timeEnd}`
ev.emit('refresh', { prog, timeNow, timeEnd, timeShow })
}
}, 1)
}
return ev
}
export default WHowler