Skip to content

Commit

Permalink
feat(plugin-compiler-web & runtime-web): add createInnerAudioContext
Browse files Browse the repository at this point in the history
  • Loading branch information
hwaphon committed Apr 1, 2024
1 parent 6ee7236 commit 78897ca
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 1 deletion.
4 changes: 3 additions & 1 deletion packages/runtime-web/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import FileAPI from './file/index'
import ImageAPI from './image'
import KeyboardAPI from './keyboard'
import LocationAPI from './location'
import AudioAPI from './media/audio'
import { my } from './my'
import NetworkAPI from './network'
import PrivateAPI from './private/index'
Expand Down Expand Up @@ -45,7 +46,8 @@ appendApis(
...convertApis(VideoAPI),
...convertApis(RouterExtensionAPI),
...convertApis(PrivateAPI),
...convertApis(AppAPI)
...convertApis(AppAPI),
...convertApis(AudioAPI)
},
DEFAULT_API_NO_CONFLICT
)
Expand Down
200 changes: 200 additions & 0 deletions packages/runtime-web/src/api/media/audio/Audio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import { defaults, EVENTS, removeValue } from './helper'

// Audio 参数 https://opendocs.alipay.com/mini/08iqsg?pathHash=d97ea89d#%E6%A6%82%E8%A7%88
export interface AudioParams {
src?: string
startTime?: number
playbackRate?: number
autoplay?: boolean
loop?: boolean
volume?: number
}

export class InnerAudio {
private params: AudioParams
private audio: HTMLAudioElement
private stopHoldOn = false // 使用 pause 模拟 stop
private callbacksMap = {
[EVENTS.PLAY]: [],
[EVENTS.PAUSE]: [],
[EVENTS.STOP]: [],
[EVENTS.ENDED]: [],
[EVENTS.TIMEUPDATE]: [],
[EVENTS.ERROR]: [],
[EVENTS.SEEKED]: [],
[EVENTS.SEEKING]: []
}

constructor(params: AudioParams) {
try {
this.params = defaults(params)
this.audio = new Audio(this.params.src)

const keys = Object.keys(this.params)
keys.forEach((key) => (this.audio[key] = this.params[key]))

this._mount() // 绑定各种事件
} catch (e) {
this._executeCallbacks(this.callbacksMap[EVENTS.ERROR])
}
}

get duration() {
return this.audio.duration
}

get paused() {
return this.audio.paused
}

get currentTime() {
return this.audio.currentTime
}

set volume(volume: number) {
this.audio.volume = volume
}

get volume() {
return this.audio.volume
}

set autoplay(autoplay: boolean) {
this.audio.autoplay = autoplay
}

get autoplay() {
return this.audio.autoplay
}

set loop(loop: boolean) {
this.audio.loop = true
}

get loop() {
return this.audio.loop
}

set playbackRate(rate: number) {
this.audio.playbackRate = rate
}

get playbackRate() {
return this.audio.playbackRate
}

private _executeCallbacks(callbacks, params) {
if (Array.isArray(callbacks) && callbacks.length > 0) {
callbacks.forEach((callback) => callback(params))
}
}

private _mount() {
const listenEvents = [
EVENTS.PLAY,
EVENTS.PAUSE,
EVENTS.ENDED,
EVENTS.SEEKED,
EVENTS.SEEKING,
EVENTS.TIMEUPDATE,
EVENTS.ERROR
]
const stopHoldOnEvents = [EVENTS.PAUSE, EVENTS.SEEKED, EVENTS.SEEKING] // 用户 stop 时为了模拟 stop 事件,屏蔽这几个事件的触发,防止用户业务误处理

listenEvents.forEach((event) =>
this.audio.addEventListener(event, (e) => {
if (this.stopHoldOn && stopHoldOnEvents.includes(event)) return
// 经过测试,音频还没播放就开始触发一次 timeupdate,做兼容处理,当前状态为未播放时,不触发 timeupdate
if (event === EVENTS.TIMEUPDATE && this.paused) return
// timeupdate 传参区分与其他事件
this._executeCallbacks(
this.callbacksMap[event],
event === EVENTS.TIMEUPDATE ? { currentTime: this.currentTime } : e
)
})
)
}

play() {
this.audio.play()
}

pause() {
this.audio.pause()
}

stop() {
this.stopHoldOn = true // 此时标记执行 stop,后续触发 seeked,seeking,pause 事件都不触发
this.pause()
this.seek(0)

setTimeout(() => {
this._executeCallbacks(this.callbacksMap[EVENTS.STOP]) // 手动触发 stop 事件
this.stopHoldOn = true // 在下一帧中重置,因为事件是异步触发的
}, 0)
}

seek(position: number) {
this.audio.currentTime = position
}

destroy() {
this.audio = null
}

onPlay(callback) {
this.callbacksMap[EVENTS.PLAY].push(callback)
}
offPlay(callback) {
removeValue(this.callbacksMap[EVENTS.PLAY], callback)
}

onPause(callback) {
this.callbacksMap[EVENTS.PAUSE].push(callback)
}
offPause(callback) {
removeValue(this.callbacksMap[EVENTS.PAUSE], callback)
}

onTimeUpdate(callback) {
this.callbacksMap[EVENTS.TIMEUPDATE].push(callback)
}
offTimeUpdate(callback) {
removeValue(this.callbacksMap[EVENTS.TIMEUPDATE], callback)
}

onStop(callback) {
this.callbacksMap[EVENTS.STOP].push(callback)
}
offStop(callback) {
removeValue(this.callbacksMap[EVENTS.STOP], callback)
}

onEnded(callback) {
this.callbacksMap[EVENTS.ENDED].push(callback)
}
offEnded(callback) {
removeValue(this.callbacksMap[EVENTS.ENDED], callback)
}

onSeeked(callback) {
this.callbacksMap[EVENTS.SEEKED].push(callback)
}
offSeeked(callback) {
removeValue(this.callbacksMap[EVENTS.SEEKED], callback)
}

onSeeking(callback) {
this.callbacksMap[EVENTS.SEEKING].push(callback)
}
offSeeking(callback) {
removeValue(this.callbacksMap[EVENTS.SEEKING], callback)
}

onError(callback) {
this.callbacksMap[EVENTS.ERROR].push(callback)
}
offError(callback) {
removeValue(this.callbacksMap[EVENTS.ERROR], callback)
}
}
29 changes: 29 additions & 0 deletions packages/runtime-web/src/api/media/audio/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const defaults = (params: AudioParams) => {
const defaultParams: AudioParams = {
startTime: 0,
playbackRate: 1,
autoplay: false,
loop: false
}

return Object.assign({}, defaultParams, params)
}

export const EVENTS = {
PLAY: 'play',
PAUSE: 'pause',
STOP: 'stop',
ENDED: 'ended',
TIMEUPDATE: 'timeupdate',
ERROR: 'error',
SEEKED: 'seeked',
SEEKING: 'seeking'
}

export const removeValue = (arr, value) => {
if (Array.isArray(arr) && arr.length > 0) {
const index = arr.indexOf(value)

if (index > -1) arr.splice(index, 1)
}
}
7 changes: 7 additions & 0 deletions packages/runtime-web/src/api/media/audio/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AudioParams, InnerAudio } from './Audio'

export default {
createInnerAudioContext(params: AudioParams) {
return new InnerAudio(params)
}
}

0 comments on commit 78897ca

Please sign in to comment.